tsdynamics 3.0.2__tar.gz → 3.0.4__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.
Files changed (192) hide show
  1. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/PKG-INFO +1 -1
  2. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/pyproject.toml +2 -1
  3. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/__init__.py +1 -1
  4. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/orbits/orbit_diagram.py +72 -8
  5. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/engine/run.py +92 -6
  6. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/continuous.py +57 -22
  7. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/LICENSE +0 -0
  8. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/README.md +0 -0
  9. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/Cargo.toml +0 -0
  10. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-core/Cargo.lock +0 -0
  11. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-core/Cargo.toml +0 -0
  12. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-core/src/bridge.rs +0 -0
  13. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-core/src/lib.rs +0 -0
  14. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/Cargo.toml +0 -0
  15. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/dde.rs +0 -0
  16. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/ensemble.rs +0 -0
  17. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/event.rs +0 -0
  18. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/integrate.rs +0 -0
  19. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/lib.rs +0 -0
  20. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/map.rs +0 -0
  21. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/problem.rs +0 -0
  22. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/rng.rs +0 -0
  23. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/sde.rs +0 -0
  24. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-engine/src/testkit.rs +0 -0
  25. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/Cargo.toml +0 -0
  26. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/builder.rs +0 -0
  27. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/eval.rs +0 -0
  28. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/lib.rs +0 -0
  29. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/op.rs +0 -0
  30. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/reference.rs +0 -0
  31. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/src/tape.rs +0 -0
  32. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/coverage_tape.rs +0 -0
  33. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/CircadianRhythm.txt +0 -0
  34. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/Lorenz.txt +0 -0
  35. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/SanUmSrisuchinwong.txt +0 -0
  36. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/SprottMore.txt +0 -0
  37. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/Torus.txt +0 -0
  38. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/fixtures/YuWang2.txt +0 -0
  39. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/gen_fixtures.py +0 -0
  40. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/golden_fixtures.rs +0 -0
  41. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-ir/tests/roundtrip.rs +0 -0
  42. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/Cargo.toml +0 -0
  43. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/src/codegen.rs +0 -0
  44. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/src/error.rs +0 -0
  45. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/src/evaluator.rs +0 -0
  46. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/src/lib.rs +0 -0
  47. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/src/shims.rs +0 -0
  48. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/tests/compile_latency.rs +0 -0
  49. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/tests/golden_fixtures.rs +0 -0
  50. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-jit/tests/interpreter_equivalence.rs +0 -0
  51. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/Cargo.toml +0 -0
  52. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/caps.rs +0 -0
  53. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/control.rs +0 -0
  54. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/dop853.rs +0 -0
  55. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/mod.rs +0 -0
  56. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/rk4.rs +0 -0
  57. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/rk45.rs +0 -0
  58. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/testkit.rs +0 -0
  59. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/explicit/tsit5.rs +0 -0
  60. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/bdf.rs +0 -0
  61. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/control.rs +0 -0
  62. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/linalg.rs +0 -0
  63. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/mod.rs +0 -0
  64. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/rosenbrock.rs +0 -0
  65. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/implicit/trbdf2.rs +0 -0
  66. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/lib.rs +0 -0
  67. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/registry.rs +0 -0
  68. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/sde/euler_maruyama.rs +0 -0
  69. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/sde/milstein.rs +0 -0
  70. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/sde/mod.rs +0 -0
  71. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/sde/testkit.rs +0 -0
  72. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/src/solver.rs +0 -0
  73. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/tests/explicit_accuracy.rs +0 -0
  74. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/tests/implicit_stiff.rs +0 -0
  75. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-solvers/tests/registry.rs +0 -0
  76. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-vm/Cargo.toml +0 -0
  77. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-vm/src/interp.rs +0 -0
  78. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-vm/src/lib.rs +0 -0
  79. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-vm/tests/golden_fixtures.rs +0 -0
  80. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/crates/tsdyn-vm/tests/oracle_equivalence.rs +0 -0
  81. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/__init__.py +0 -0
  82. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/_result.py +0 -0
  83. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/__init__.py +0 -0
  84. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/_common.py +0 -0
  85. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/attractors.py +0 -0
  86. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/basins.py +0 -0
  87. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/continuation.py +0 -0
  88. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/basins/metrics.py +0 -0
  89. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/chaos/__init__.py +0 -0
  90. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/chaos/_common.py +0 -0
  91. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/chaos/expansion.py +0 -0
  92. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/chaos/gali.py +0 -0
  93. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/chaos/zero_one.py +0 -0
  94. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/__init__.py +0 -0
  95. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/_common.py +0 -0
  96. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/_scaling.py +0 -0
  97. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/correlation.py +0 -0
  98. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/fixedmass.py +0 -0
  99. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/dimensions/generalized.py +0 -0
  100. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/embedding/__init__.py +0 -0
  101. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/embedding/_common.py +0 -0
  102. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/embedding/delay.py +0 -0
  103. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/embedding/dimension.py +0 -0
  104. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/embedding/embed.py +0 -0
  105. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/__init__.py +0 -0
  106. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/core.py +0 -0
  107. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/dispersion.py +0 -0
  108. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/lz.py +0 -0
  109. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/multiscale.py +0 -0
  110. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/permutation.py +0 -0
  111. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/entropy/sample.py +0 -0
  112. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/fixedpoints/__init__.py +0 -0
  113. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/fixedpoints/_common.py +0 -0
  114. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/fixedpoints/fixed.py +0 -0
  115. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/fixedpoints/periodic.py +0 -0
  116. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/lyapunov/__init__.py +0 -0
  117. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/lyapunov/from_data.py +0 -0
  118. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/orbits/__init__.py +0 -0
  119. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/orbits/poincare.py +0 -0
  120. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/orbits/return_map.py +0 -0
  121. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/recurrence/__init__.py +0 -0
  122. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/recurrence/_common.py +0 -0
  123. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/recurrence/matrix.py +0 -0
  124. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/recurrence/rqa.py +0 -0
  125. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/recurrence/windowed.py +0 -0
  126. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/surrogate/__init__.py +0 -0
  127. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/surrogate/_common.py +0 -0
  128. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/surrogate/generators.py +0 -0
  129. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/surrogate/hypothesis.py +0 -0
  130. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/analysis/surrogate/statistics.py +0 -0
  131. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/data/__init__.py +0 -0
  132. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/data/sampling.py +0 -0
  133. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/data/trajectory.py +0 -0
  134. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/__init__.py +0 -0
  135. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/_base.py +0 -0
  136. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/_crossings.py +0 -0
  137. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/_variational.py +0 -0
  138. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/ensemble.py +0 -0
  139. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/poincare.py +0 -0
  140. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/projected.py +0 -0
  141. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/stroboscopic.py +0 -0
  142. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/tangent.py +0 -0
  143. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/derived/wrapped.py +0 -0
  144. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/engine/__init__.py +0 -0
  145. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/engine/compile.py +0 -0
  146. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/engine/problem.py +0 -0
  147. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/engine/symbols.py +0 -0
  148. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/errors.py +0 -0
  149. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/__init__.py +0 -0
  150. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/_accessors.py +0 -0
  151. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/_dde_lyapunov.py +0 -0
  152. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/base.py +0 -0
  153. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/delay.py +0 -0
  154. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/discrete.py +0 -0
  155. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/protocol.py +0 -0
  156. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/families/stochastic.py +0 -0
  157. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/plugins.py +0 -0
  158. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/py.typed +0 -0
  159. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/registry.py +0 -0
  160. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/solvers/__init__.py +0 -0
  161. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/solvers/explicit.py +0 -0
  162. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/solvers/implicit.py +0 -0
  163. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/solvers/select.py +0 -0
  164. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/solvers/stochastic.py +0 -0
  165. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/__init__.py +0 -0
  166. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/__init__.py +0 -0
  167. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/chaotic_attractors.py +0 -0
  168. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/chem_bio_systems.py +0 -0
  169. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/climate_geophysics.py +0 -0
  170. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/coupled_systems.py +0 -0
  171. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/delayed_systems.py +0 -0
  172. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/exotic_systems.py +0 -0
  173. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/oscillatory_systems.py +0 -0
  174. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/physical_systems.py +0 -0
  175. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/continuous/population_dynamics.py +0 -0
  176. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/__init__.py +0 -0
  177. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/chaotic_maps.py +0 -0
  178. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/exotic_maps.py +0 -0
  179. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/geometric_maps.py +0 -0
  180. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/polynomial_maps.py +0 -0
  181. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/systems/discrete/population_maps.py +0 -0
  182. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/transforms/__init__.py +0 -0
  183. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/transforms/_common.py +0 -0
  184. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/transforms/features.py +0 -0
  185. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/transforms/preprocessing.py +0 -0
  186. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/transforms/spectral.py +0 -0
  187. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/utils/__init__.py +0 -0
  188. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/utils/general.py +0 -0
  189. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/utils/grids.py +0 -0
  190. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/utils/sagitta_dt.py +0 -0
  191. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/viz/__init__.py +0 -0
  192. {tsdynamics-3.0.2 → tsdynamics-3.0.4}/src/tsdynamics/viz/spec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsdynamics
3
- Version: 3.0.2
3
+ Version: 3.0.4
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Operating System :: OS Independent
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "tsdynamics"
7
- version = "3.0.2"
7
+ version = "3.0.4"
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"
@@ -62,6 +62,7 @@ lz = ["lzcomplexity>=0.9"]
62
62
  dev = [
63
63
  "pytest>=8.0",
64
64
  "pytest-cov>=5.0",
65
+ "pytest-xdist>=3.6",
65
66
  "ruff>=0.6",
66
67
  "mypy>=1.10",
67
68
  "pre-commit>=3.8",
@@ -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.2"
127
+ __version__ = "3.0.4"
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
@@ -164,6 +164,47 @@ def _count_branches(col: np.ndarray, rtol: float) -> int:
164
164
  return 1 + int(np.count_nonzero(np.diff(s) > rtol * span))
165
165
 
166
166
 
167
+ def _record_via_iterate(
168
+ current: Any, start: Any, transient: int, n: int, idx: list[int]
169
+ ) -> tuple[np.ndarray, np.ndarray]:
170
+ """Record one parameter value on the Rust engine, in a single ``iterate`` call.
171
+
172
+ Resolve the initial condition explicitly and iterate ``transient + n`` steps
173
+ in one FFI round-trip, then slice off the transient. ``max_retries=1`` with an
174
+ explicit ``ic`` makes a divergent value raise ``RuntimeError`` (no random-IC
175
+ retry) — the caller turns that into an empty record set, exactly as the
176
+ per-step path does. Returns the recorded points and the final state (the
177
+ carry-over initial condition for the next value).
178
+ """
179
+ ic_resolved = current.resolve_ic(start)
180
+ traj = current.iterate(steps=transient + n, ic=ic_resolved, max_retries=1)
181
+ y = traj.y
182
+ rec = np.asarray(y[transient : transient + n][:, idx], dtype=float)
183
+ # A zero-length run (``transient + n == 0``) yields no rows; the carry-over
184
+ # final state is then just the resolved initial condition — matching the old
185
+ # step-loop's ``current.state()`` after taking no steps.
186
+ last = y[-1].copy() if y.shape[0] else np.asarray(ic_resolved, dtype=float).reshape(current.dim)
187
+ return rec, last
188
+
189
+
190
+ def _record_via_step(
191
+ current: Any, start: Any, transient: int, n: int, idx: list[int]
192
+ ) -> tuple[np.ndarray, np.ndarray]:
193
+ """Record one parameter value via the per-step protocol path (a ``step()`` loop).
194
+
195
+ The fallback for flow wrappers (``PoincareMap`` / ``StroboscopicMap``), maps
196
+ whose ``_step`` will not lower to the engine IR, and wheel-free environments.
197
+ Returns the recorded points and the final state.
198
+ """
199
+ current.reinit(start)
200
+ for _ in range(transient):
201
+ current.step()
202
+ rec = np.empty((n, len(idx)))
203
+ for i in range(n):
204
+ rec[i] = current.step()[idx]
205
+ return rec, current.state()
206
+
207
+
167
208
  def orbit_diagram(
168
209
  sys: Any,
169
210
  param: str,
@@ -241,21 +282,44 @@ def orbit_diagram(
241
282
 
242
283
  import warnings
243
284
 
285
+ from tsdynamics.engine.compile import TapeCompileError
286
+ from tsdynamics.engine.run import EngineNotAvailableError
287
+ from tsdynamics.families import DiscreteMap
288
+
244
289
  values_arr = np.asarray(list(values), dtype=float)
245
290
  points: list[np.ndarray] = []
246
291
  state: np.ndarray | None = None
247
292
 
293
+ # A genuine DiscreteMap iterates on the Rust engine: the whole transient +
294
+ # record run for one parameter value becomes a single engine call (one FFI
295
+ # round-trip) rather than ``transient + n`` Python ``step()`` calls — the
296
+ # per-value bottleneck this stream removes (Logistic 600×120: ~9× faster).
297
+ # Flow wrappers (PoincareMap / StroboscopicMap) have no ``iterate`` and keep
298
+ # the per-step protocol path; a map whose ``_step`` will not lower to the IR,
299
+ # or a wheel-free environment with no compiled engine, falls back to it too
300
+ # (the decision is taken once and latched for the rest of the sweep). Both
301
+ # paths iterate the *same* lowered ``_step``, so a periodic window converges to
302
+ # the identical cycle and — where the engine and NumPy agree bit-for-bit (e.g.
303
+ # the logistic map) — the whole diagram is byte-identical; a chaotic window
304
+ # records the same attractor (the engine ``iterate`` being the canonical map
305
+ # runner).
306
+ use_engine = isinstance(sys, DiscreteMap)
307
+
248
308
  for v in values_arr:
249
309
  current = sys.with_params(**{param: v})
250
310
  start = state if (carry_state and state is not None) else ic
251
311
  try:
252
- current.reinit(start)
253
- for _ in range(transient):
254
- current.step()
255
- rec = np.empty((n, len(idx)))
256
- for i in range(n):
257
- u = current.step()
258
- rec[i] = u[idx]
312
+ if use_engine:
313
+ try:
314
+ rec, last = _record_via_iterate(current, start, transient, n, idx)
315
+ except (TapeCompileError, EngineNotAvailableError):
316
+ # This map cannot run on the engine (a non-lowerable step, or
317
+ # no compiled wheel): fall back to the protocol path for this
318
+ # value and the rest of the sweep.
319
+ use_engine = False
320
+ rec, last = _record_via_step(current, start, transient, n, idx)
321
+ else:
322
+ rec, last = _record_via_step(current, start, transient, n, idx)
259
323
  except RuntimeError as exc:
260
324
  # One divergent value must not discard the whole sweep: record an
261
325
  # empty point set and restart the next value from `ic`.
@@ -270,7 +334,7 @@ def orbit_diagram(
270
334
  continue
271
335
  points.append(rec)
272
336
  if carry_state:
273
- state = current.state()
337
+ state = last
274
338
 
275
339
  meta = {
276
340
  "system": type(sys).__name__,
@@ -526,7 +526,15 @@ def _run_continuous(
526
526
 
527
527
  eng = _engine()
528
528
  y = _engine_integrate_dense(
529
- eng, problem, t_eval, method=method, rtol=rtol, atol=atol, jit=(backend == "jit")
529
+ eng,
530
+ _primary_tape(problem).to_arrays(),
531
+ problem.ic,
532
+ problem.params_vec(),
533
+ t_eval,
534
+ method=method,
535
+ rtol=rtol,
536
+ atol=atol,
537
+ jit=(backend == "jit"),
530
538
  )
531
539
  y = np.asarray(y, dtype=np.float64)
532
540
  if not np.all(np.isfinite(y)):
@@ -537,6 +545,74 @@ def _run_continuous(
537
545
  return y
538
546
 
539
547
 
548
+ def _step_continuous(
549
+ tape_arrays: tuple,
550
+ ic: np.ndarray,
551
+ params_vec: np.ndarray,
552
+ t_eval: np.ndarray,
553
+ *,
554
+ method: str,
555
+ rtol: float,
556
+ atol: float,
557
+ jit: bool,
558
+ name: str,
559
+ ) -> np.ndarray:
560
+ """Integrate one dense ODE span from pre-marshalled tape arrays — the per-step seam.
561
+
562
+ The lean inner core of
563
+ :meth:`~tsdynamics.families.continuous.ContinuousSystem.step`: it performs
564
+ exactly the engine call and finiteness guard :func:`_run_continuous` does for an
565
+ ODE on the compiled engine, but takes the already-marshalled tape wire arrays
566
+ (cached once at ``reinit`` — they are loop-invariant) plus the live parameter
567
+ vector, skipping the per-call tape re-marshalling, ``Problem`` construction and
568
+ output-grid build that the full :func:`integrate` entry point pays. It is
569
+ therefore **answer-identical** to :func:`_run_continuous` over the same inputs
570
+ (stream WS-INVHOIST); it serves only the constant-/small-``dt`` stepping loops
571
+ (Poincaré refinement, basins over flows, the streaming protocol), never a
572
+ user-facing :class:`~tsdynamics.families.Trajectory` (which keeps its
573
+ provenance via :func:`integrate`).
574
+
575
+ Parameters
576
+ ----------
577
+ tape_arrays : tuple
578
+ The RHS tape's engine wire arrays (:meth:`Tape.to_arrays`), marshalled once
579
+ by the caller and reused across the loop.
580
+ ic : ndarray, shape (dim,)
581
+ The state to start this span from.
582
+ params_vec : ndarray
583
+ Live control-parameter values, read per step so a mid-loop parameter change
584
+ still takes effect — identical to the pre-hoist path.
585
+ t_eval : ndarray
586
+ The (two-node) output grid for this span.
587
+ method, rtol, atol, jit : str, float, float, bool
588
+ Solver configuration, resolved once by ``reinit``.
589
+ name : str
590
+ System name, for the divergence error message.
591
+
592
+ Returns
593
+ -------
594
+ ndarray, shape (len(t_eval), dim)
595
+
596
+ Raises
597
+ ------
598
+ RuntimeError
599
+ If the integration diverged or the step collapsed (non-finite output) —
600
+ the same loud-divergence contract as :func:`_run_continuous`.
601
+ """
602
+ eng = _engine()
603
+ y = np.asarray(
604
+ _engine_integrate_dense(
605
+ eng, tape_arrays, ic, params_vec, t_eval, method=method, rtol=rtol, atol=atol, jit=jit
606
+ ),
607
+ dtype=np.float64,
608
+ )
609
+ if not np.isfinite(y).all():
610
+ raise RuntimeError(
611
+ f"{name}: integration diverged or the step collapsed before reaching the final time."
612
+ )
613
+ return y
614
+
615
+
540
616
  def _run_dde(
541
617
  problem: DDEProblem,
542
618
  t_eval: np.ndarray,
@@ -917,7 +993,9 @@ def sde_ensemble_final(
917
993
 
918
994
  def _engine_integrate_dense(
919
995
  eng: Any,
920
- problem: Problem,
996
+ tape_arrays: tuple,
997
+ ic: np.ndarray,
998
+ params_vec: np.ndarray,
921
999
  t_eval: np.ndarray,
922
1000
  *,
923
1001
  method: str,
@@ -925,11 +1003,19 @@ def _engine_integrate_dense(
925
1003
  atol: float,
926
1004
  jit: bool,
927
1005
  ) -> np.ndarray:
928
- """Dispatch a dense single-trajectory integration to the engine."""
1006
+ """Dispatch a dense single-trajectory integration to the engine.
1007
+
1008
+ ``tape_arrays`` is the RHS tape's wire tuple (:meth:`Tape.to_arrays` — the
1009
+ drift tape for an SDE). Taking the marshalled arrays as an argument rather than
1010
+ deriving them here lets a hot stepping loop pass arrays it marshalled once
1011
+ (:func:`_step_continuous`) instead of rebuilding the tuple per step (stream
1012
+ WS-INVHOIST), while the single-shot :func:`integrate` path marshals them inline
1013
+ at the call site.
1014
+ """
929
1015
  return eng.integrate_dense(
930
- *_primary_tape(problem).to_arrays(),
931
- np.ascontiguousarray(problem.ic, dtype=np.float64),
932
- problem.params_vec(),
1016
+ *tape_arrays,
1017
+ np.ascontiguousarray(ic, dtype=np.float64),
1018
+ params_vec,
933
1019
  np.ascontiguousarray(t_eval, dtype=np.float64),
934
1020
  method,
935
1021
  float(rtol),
@@ -165,8 +165,11 @@ class ContinuousSystem(SystemBase, ABC):
165
165
  # Per-step integration context cached by ``reinit`` so a repeated constant-``dt``
166
166
  # stepping loop pays the fixed per-call overhead (solver-registry resolve,
167
167
  # Jacobian decision, output-grid build, provenance, Trajectory wrap) once at
168
- # reinit instead of on every ``step`` (stream WS-STEPBUF).
168
+ # reinit instead of on every ``step`` (stream WS-STEPBUF). ``_step_tape_arrays``
169
+ # caches the engine wire arrays of the (loop-invariant) tape so the per-``dt``
170
+ # loop reuses them rather than re-marshalling the tuple each call (WS-INVHOIST).
169
171
  _step_method_canonical: str | None = None
172
+ _step_tape_arrays: Any = None
170
173
 
171
174
  # ------------------------------------------------------------------ #
172
175
  # Subclass interface
@@ -304,7 +307,16 @@ class ContinuousSystem(SystemBase, ABC):
304
307
  # Cache the canonical kernel name (``"RK45"`` → ``"rk45"``) so the per-step
305
308
  # loop hits the engine core directly without re-resolving every call.
306
309
  self._step_method_canonical = resolution.name
307
- self._engine_problem = ode_problem(self, ic=ic_arr, t0=t0, **resolution.build_kwargs)
310
+ prob = ode_problem(self, ic=ic_arr, t0=t0, **resolution.build_kwargs)
311
+ # Marshal the (loop-invariant) tape to its engine wire arrays once here so the
312
+ # per-``dt`` ``step`` loop reuses them instead of rebuilding the tuple on every
313
+ # call (stream WS-INVHOIST). Re-derived on each ``reinit`` (a sweep reinits
314
+ # per parameter value), so a re-lowered tape is always picked up. Marshal before
315
+ # publishing the problem so a (theoretical) marshalling failure can't leave a new
316
+ # ``_engine_problem`` paired with a stale ``_step_tape_arrays``.
317
+ step_arrays = prob.tape.to_arrays()
318
+ self._engine_problem = prob
319
+ self._step_tape_arrays = step_arrays
308
320
  self._step_rtol = float(rtol)
309
321
  self._step_atol = float(atol)
310
322
  self._state_now = ic_arr.copy()
@@ -323,14 +335,18 @@ class ContinuousSystem(SystemBase, ABC):
323
335
  Each call integrates **exactly one** ``dt`` from the live ``(state, t)``,
324
336
  returning byte-for-byte the trajectory the released per-``dt`` path
325
337
  produced — there is no batching, so the numbers are unchanged for every
326
- method, adaptive or fixed-step (stream WS-STEPBUF). The speedup comes
327
- only from skipping fixed per-call overhead: ``step`` reuses the tape and
328
- canonical kernel name cached by :meth:`reinit` and calls the engine's lean
329
- dense-output core (:func:`~tsdynamics.engine.run._run_continuous`)
330
- directly, so a constant-``dt`` stepping loop (Poincaré refinement, basins
338
+ method, adaptive or fixed-step (streams WS-STEPBUF, WS-INVHOIST). The
339
+ speedup comes only from hoisting fixed per-call overhead out of the loop:
340
+ ``step`` reuses the tape, its canonical kernel name and its marshalled
341
+ engine wire arrays — all cached by :meth:`reinit` — and calls the engine's
342
+ lean dense-output core (:func:`~tsdynamics.engine.run._step_continuous`)
343
+ directly. So a constant-``dt`` stepping loop (Poincaré refinement, basins
331
344
  over flows) skips the solver-registry resolve, the implicit-Jacobian
332
- decision, provenance assembly and the :class:`Trajectory` wrap that the
333
- full :meth:`integrate` entry point pays on every call.
345
+ decision, the tape re-marshalling, the output-grid ``arange``/append,
346
+ provenance assembly and the :class:`Trajectory` wrap that the full
347
+ :meth:`integrate` entry point pays on every call. The control-parameter
348
+ vector is still read live each step, so the live-stepper semantics are
349
+ unchanged.
334
350
 
335
351
  A batch-ahead variant that integrated a whole chunk in one engine call was
336
352
  rejected: a chunked adaptive integration is *not* equal to N single-``dt``
@@ -339,31 +355,50 @@ class ContinuousSystem(SystemBase, ABC):
339
355
  ``max_lyapunov``. The durable amortisation is the resumable engine stepper
340
356
  (WS-STEPPER), which advances without re-seeding and stays answer-exact.
341
357
  """
342
- from tsdynamics.engine.problem import ODEProblem
343
- from tsdynamics.engine.run import _run_continuous
344
- from tsdynamics.utils.grids import make_output_grid
358
+ from tsdynamics.engine.run import _step_continuous
345
359
 
346
360
  if self._engine_problem is None:
347
361
  self.reinit()
348
362
  dt = float(n_or_dt) if n_or_dt is not None else self._default_step_dt
349
363
 
350
364
  t0 = self._t_now
351
- # The same two-node output grid the full ``integrate`` would build for a
352
- # single ``dt`` span — so ``step`` is bit-identical to a per-``dt``
353
- # ``integrate`` from the live state.
354
- t_eval = make_output_grid(t0, t0 + dt, dt)
355
- prob = ODEProblem(tape=self._engine_problem.tape, ic=self._state_now, t0=t0, system=self)
356
- y = _run_continuous(
357
- prob,
365
+ tf = t0 + dt
366
+ # The two-node grid ``make_output_grid(t0, tf, dt)`` builds for a single ``dt``
367
+ # span, assembled directly to skip its ``arange``/append (WS-INVHOIST). When the
368
+ # span clears ``1e-9`` the helper is byte-for-byte exactly ``[t0, tf]``: that sits
369
+ # a thousandfold above its ``1e-12`` append tolerance (``t_arr[-1] < tf - 1e-12``)
370
+ # and above the float-subtraction rounding even at large ``t0``, and a single
371
+ # ``dt`` span never yields more than two nodes — so the shortcut is identical
372
+ # there (the regime of every real step; verified bit-for-bit over a wide
373
+ # ``t0``/``dt`` fuzz). The rare remainder — a sub-``1e-9`` step (whose helper grid
374
+ # may degenerate to a single un-advanced node) or a non-forward / non-positive
375
+ # ``dt`` (which must raise the canonical
376
+ # :class:`~tsdynamics.errors.InvalidParameterError`) — defers to the helper so
377
+ # ``step`` stays byte-identical to the pre-hoist path for *every* input.
378
+ if tf - t0 > 1e-9:
379
+ t_eval = np.array([t0, tf], dtype=np.float64)
380
+ else:
381
+ from tsdynamics.utils.grids import make_output_grid
382
+
383
+ t_eval = make_output_grid(t0, tf, dt)
384
+ y = _step_continuous(
385
+ self._step_tape_arrays,
386
+ self._state_now,
387
+ self._engine_problem.params_vec(),
358
388
  t_eval,
359
389
  method=self._step_method_canonical,
360
390
  rtol=self._step_rtol,
361
391
  atol=self._step_atol,
362
- backend=self._step_backend,
392
+ jit=self._step_backend == "jit",
393
+ name=type(self).__name__,
363
394
  )
364
395
  state = np.asarray(y[-1], dtype=float)
365
- self._t_now = t0 + dt
366
- self._state_now = state.copy()
396
+ # The state/time advance writes private framework attributes that always pass
397
+ # straight through ``SystemBase.__setattr__`` (underscore-prefixed) — go direct
398
+ # to ``object.__setattr__`` so the hot loop skips the param-typo guard's
399
+ # ``params`` membership check on every step (WS-INVHOIST).
400
+ object.__setattr__(self, "_t_now", tf)
401
+ object.__setattr__(self, "_state_now", state.copy())
367
402
  return state.copy()
368
403
 
369
404
  def state(self) -> np.ndarray:
File without changes
File without changes
File without changes