stochasticforceinference 2.0.3__tar.gz → 2.1.0__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 (209) hide show
  1. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/AGENTS.md +73 -11
  2. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/MANIFEST.in +1 -0
  3. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/PKG-INFO +103 -44
  4. stochasticforceinference-2.1.0/README.md +218 -0
  5. stochasticforceinference-2.1.0/SFI/AGENT_GUIDE.md +231 -0
  6. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/__init__.py +24 -4
  7. stochasticforceinference-2.1.0/SFI/__main__.py +70 -0
  8. stochasticforceinference-2.1.0/SFI/_version.py +36 -0
  9. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/pairs.py +60 -13
  10. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/__init__.py +10 -1
  11. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/assess.py +21 -3
  12. stochasticforceinference-2.1.0/SFI/diagnostics/diffusion_check.py +63 -0
  13. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/dynamics_order.py +69 -71
  14. stochasticforceinference-2.1.0/SFI/diagnostics/finite_dt.py +190 -0
  15. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/plotting.py +22 -9
  16. stochasticforceinference-2.1.0/SFI/diagnostics/psd.py +93 -0
  17. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/report.py +116 -9
  18. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/residual_tests.py +57 -18
  19. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/diagnostics/residuals.py +326 -4
  20. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/__init__.py +3 -1
  21. stochasticforceinference-2.1.0/SFI/inference/_oli_diffusion.py +667 -0
  22. stochasticforceinference-2.1.0/SFI/inference/_oli_instrument.py +1049 -0
  23. stochasticforceinference-2.1.0/SFI/inference/_uli_constant_noise.py +931 -0
  24. stochasticforceinference-2.1.0/SFI/inference/_uli_diffusion.py +348 -0
  25. stochasticforceinference-2.1.0/SFI/inference/_uli_drift_check.py +103 -0
  26. stochasticforceinference-2.1.0/SFI/inference/_uli_model_free.py +729 -0
  27. stochasticforceinference-2.1.0/SFI/inference/_uli_path_resolution.py +143 -0
  28. stochasticforceinference-2.1.0/SFI/inference/_uli_stride.py +258 -0
  29. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/base.py +856 -76
  30. stochasticforceinference-2.1.0/SFI/inference/graph_diffusion.py +523 -0
  31. stochasticforceinference-2.1.0/SFI/inference/overdamped.py +2268 -0
  32. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/driver.py +26 -4
  33. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow_multi.py +143 -33
  34. stochasticforceinference-2.1.0/SFI/inference/parametric_core/frame_extras.py +112 -0
  35. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/precompute.py +58 -26
  36. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/runner.py +367 -84
  37. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/solve.py +165 -94
  38. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/result.py +18 -5
  39. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/__init__.py +20 -1
  40. stochasticforceinference-2.1.0/SFI/inference/sparse/exhaustive.py +107 -0
  41. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/hillclimb.py +9 -4
  42. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/result.py +215 -9
  43. stochasticforceinference-2.1.0/SFI/inference/sparse/units.py +514 -0
  44. stochasticforceinference-2.1.0/SFI/inference/underdamped.py +3445 -0
  45. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/integrate/__init__.py +11 -1
  46. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/integrate/api.py +559 -50
  47. stochasticforceinference-2.1.0/SFI/integrate/integrand.py +659 -0
  48. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/integrate/timeops.py +23 -0
  49. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/base.py +115 -8
  50. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/chunked.py +2 -3
  51. stochasticforceinference-2.1.0/SFI/langevin/graph_noise.py +498 -0
  52. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/noise.py +9 -0
  53. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/overdamped.py +43 -23
  54. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/underdamped.py +94 -56
  55. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/factory.py +19 -0
  56. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/base.py +16 -0
  57. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/__init__.py +2 -0
  58. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/dispatcher.py +351 -337
  59. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/specs.py +93 -3
  60. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/leaf.py +56 -3
  61. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/derivative.py +41 -12
  62. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/slice.py +42 -3
  63. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/params.py +25 -9
  64. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/stateexpr.py +27 -3
  65. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/dataset.py +104 -63
  66. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/degrade.py +201 -64
  67. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/reserved_extras.py +29 -5
  68. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/utils/formatting.py +32 -4
  69. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/utils/maths.py +102 -7
  70. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/utils/neighbors.py +11 -3
  71. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/utils/plotting.py +253 -52
  72. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/PKG-INFO +103 -44
  73. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/SOURCES.txt +24 -1
  74. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/requires.txt +3 -2
  75. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/abp.py +7 -3
  76. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/coarse_grain.py +26 -16
  77. stochasticforceinference-2.1.0/examples/_gallery_utils/janus_colloids.py +475 -0
  78. stochasticforceinference-2.1.0/examples/experimental_data/generate_tweezer_csv.py +53 -0
  79. stochasticforceinference-2.1.0/examples/gallery/abp_align_demo.py +456 -0
  80. stochasticforceinference-2.1.0/examples/gallery/abp_nonreciprocal_demo.py +606 -0
  81. stochasticforceinference-2.1.0/examples/gallery/abp_to_spde_demo.py +834 -0
  82. stochasticforceinference-2.1.0/examples/gallery/advanced/flocking_3d_demo.py +556 -0
  83. stochasticforceinference-2.1.0/examples/gallery/advanced/multi_experiment_demo.py +389 -0
  84. stochasticforceinference-2.1.0/examples/gallery/advanced/nn_force_demo.py +405 -0
  85. stochasticforceinference-2.1.0/examples/gallery/anisotropic_diffusion_demo.py +379 -0
  86. stochasticforceinference-2.1.0/examples/gallery/custom_basis_demo.py +327 -0
  87. stochasticforceinference-2.1.0/examples/gallery/diagnostics_demo.py +303 -0
  88. stochasticforceinference-2.1.0/examples/gallery/dynamics_order_demo.py +291 -0
  89. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/gallery/entropy_production_demo.py +152 -135
  90. stochasticforceinference-2.1.0/examples/gallery/entropy_production_underdamped_demo.py +493 -0
  91. stochasticforceinference-2.1.0/examples/gallery/experimental_workflow_demo.py +413 -0
  92. stochasticforceinference-2.1.0/examples/gallery/gray_scott_demo.py +711 -0
  93. stochasticforceinference-2.1.0/examples/gallery/home_range_demo.py +377 -0
  94. stochasticforceinference-2.1.0/examples/gallery/janus_colloids_demo.py +457 -0
  95. stochasticforceinference-2.1.0/examples/gallery/limitcycle_demo.py +328 -0
  96. stochasticforceinference-2.1.0/examples/gallery/lorenz_demo.py +369 -0
  97. stochasticforceinference-2.1.0/examples/gallery/lotka_volterra_demo.py +593 -0
  98. stochasticforceinference-2.1.0/examples/gallery/multiplicative_diffusion_demo.py +368 -0
  99. stochasticforceinference-2.1.0/examples/gallery/ou_demo.py +429 -0
  100. stochasticforceinference-2.1.0/examples/gallery/time_dependent_forcing_demo.py +268 -0
  101. stochasticforceinference-2.1.0/examples/gallery/time_fourier_demo.py +341 -0
  102. stochasticforceinference-2.1.0/examples/gallery/van_der_pol_demo.py +596 -0
  103. stochasticforceinference-2.1.0/examples/gallery/velocity_dependent_noise_demo.py +372 -0
  104. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/pyproject.toml +24 -8
  105. stochasticforceinference-2.1.0/tests/test_agent_guide.py +162 -0
  106. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/tests/test_parametric_mask_abp.py +1 -0
  107. stochasticforceinference-2.1.0/tests/test_version.py +50 -0
  108. stochasticforceinference-2.0.3/README.md +0 -163
  109. stochasticforceinference-2.0.3/SFI/inference/overdamped.py +0 -1497
  110. stochasticforceinference-2.0.3/SFI/inference/underdamped.py +0 -1857
  111. stochasticforceinference-2.0.3/SFI/integrate/integrand.py +0 -402
  112. stochasticforceinference-2.0.3/examples/experimental_data/generate_tweezer_csv.py +0 -35
  113. stochasticforceinference-2.0.3/examples/gallery/abp_align_demo.py +0 -574
  114. stochasticforceinference-2.0.3/examples/gallery/abp_nonreciprocal_demo.py +0 -529
  115. stochasticforceinference-2.0.3/examples/gallery/abp_to_spde_demo.py +0 -602
  116. stochasticforceinference-2.0.3/examples/gallery/advanced/flocking_3d_demo.py +0 -314
  117. stochasticforceinference-2.0.3/examples/gallery/advanced/multi_experiment_demo.py +0 -347
  118. stochasticforceinference-2.0.3/examples/gallery/advanced/nn_force_demo.py +0 -521
  119. stochasticforceinference-2.0.3/examples/gallery/anisotropic_diffusion_demo.py +0 -234
  120. stochasticforceinference-2.0.3/examples/gallery/custom_basis_demo.py +0 -254
  121. stochasticforceinference-2.0.3/examples/gallery/diagnostics_demo.py +0 -150
  122. stochasticforceinference-2.0.3/examples/gallery/dynamics_order_demo.py +0 -271
  123. stochasticforceinference-2.0.3/examples/gallery/entropy_production_underdamped_demo.py +0 -464
  124. stochasticforceinference-2.0.3/examples/gallery/experimental_workflow_demo.py +0 -216
  125. stochasticforceinference-2.0.3/examples/gallery/gray_scott_demo.py +0 -574
  126. stochasticforceinference-2.0.3/examples/gallery/home_range_demo.py +0 -394
  127. stochasticforceinference-2.0.3/examples/gallery/limitcycle_demo.py +0 -213
  128. stochasticforceinference-2.0.3/examples/gallery/lorenz_demo.py +0 -219
  129. stochasticforceinference-2.0.3/examples/gallery/lotka_volterra_demo.py +0 -319
  130. stochasticforceinference-2.0.3/examples/gallery/multiplicative_diffusion_demo.py +0 -240
  131. stochasticforceinference-2.0.3/examples/gallery/ou_demo.py +0 -413
  132. stochasticforceinference-2.0.3/examples/gallery/time_dependent_forcing_demo.py +0 -156
  133. stochasticforceinference-2.0.3/examples/gallery/time_fourier_demo.py +0 -234
  134. stochasticforceinference-2.0.3/examples/gallery/van_der_pol_demo.py +0 -245
  135. stochasticforceinference-2.0.3/examples/gallery/velocity_dependent_noise_demo.py +0 -202
  136. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/CONTRIBUTING.md +0 -0
  137. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/GALLERY_STYLE_GUIDE.md +0 -0
  138. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/LICENSE +0 -0
  139. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/__init__.py +0 -0
  140. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/constants.py +0 -0
  141. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/linear.py +0 -0
  142. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/monomials.py +0 -0
  143. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/bases/spde.py +0 -0
  144. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/optimizers.py +0 -0
  145. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/__init__.py +0 -0
  146. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/banded.py +0 -0
  147. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/covariance.py +0 -0
  148. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow.py +0 -0
  149. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow_ud.py +0 -0
  150. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/gram.py +0 -0
  151. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/jacobians.py +0 -0
  152. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/serialization.py +0 -0
  153. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/base.py +0 -0
  154. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/beam.py +0 -0
  155. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/greedy.py +0 -0
  156. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/lasso.py +0 -0
  157. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/metrics.py +0 -0
  158. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/scorer.py +0 -0
  159. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparse/stlsq.py +0 -0
  160. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/inference/sparsity.py +0 -0
  161. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/integrate/rk4.py +0 -0
  162. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/langevin/__init__.py +0 -0
  163. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/__init__.py +0 -0
  164. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/basis.py +0 -0
  165. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/core/runtime.py +0 -0
  166. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/interactor.py +0 -0
  167. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/__init__.py +0 -0
  168. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_base.py +0 -0
  169. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_eval_compiler.py +0 -0
  170. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_fd_atoms.py +0 -0
  171. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_grid.py +0 -0
  172. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_sectors.py +0 -0
  173. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/memhint.py +0 -0
  174. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/__init__.py +0 -0
  175. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/contract.py +0 -0
  176. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/prepare.py +0 -0
  177. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/stencils.py +0 -0
  178. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/__init__.py +0 -0
  179. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/concat.py +0 -0
  180. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/einsum.py +0 -0
  181. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/linear.py +0 -0
  182. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/mapn.py +0 -0
  183. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/reshape_rank.py +0 -0
  184. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/psf.py +0 -0
  185. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/sf.py +0 -0
  186. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/statefunc/structexpr.py +0 -0
  187. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/__init__.py +0 -0
  188. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/collection.py +0 -0
  189. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/trajectory/io.py +0 -0
  190. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/SFI/utils/__init__.py +0 -0
  191. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/dependency_links.txt +0 -0
  192. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/top_level.txt +0 -0
  193. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/__init__.py +0 -0
  194. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/bench_utils.py +0 -0
  195. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/helpers.py +0 -0
  196. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/_gallery_utils/scenario_picker.py +0 -0
  197. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/experimental_data/_analyze_results.py +0 -0
  198. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/experimental_data/_expanded_basis.py +0 -0
  199. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_align_demo.py +0 -0
  200. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_config.py +0 -0
  201. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_demo.py +0 -0
  202. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_infer.py +0 -0
  203. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_plot.py +0 -0
  204. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_simulate.py +0 -0
  205. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_pursuit_demo.py +0 -0
  206. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/setup.cfg +0 -0
  207. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/tests/test_dual_mask.py +0 -0
  208. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/tests/test_parametric_mask.py +0 -0
  209. {stochasticforceinference-2.0.3 → stochasticforceinference-2.1.0}/tests/test_same_particle_jacobian.py +0 -0
@@ -4,6 +4,10 @@
4
4
  > agents (GitHub Copilot, Claude Code, Cursor, …) on the Stochastic
5
5
  > Force Inference (SFI) repository. Human contributors should read
6
6
  > [`CONTRIBUTING.md`](CONTRIBUTING.md).
7
+ >
8
+ > **Using SFI as a library** (analysing data, not modifying SFI)? Read
9
+ > [`SFI/AGENT_GUIDE.md`](SFI/AGENT_GUIDE.md) instead: it ships inside the
10
+ > installed package (`python -m SFI guide`).
7
11
 
8
12
  ---
9
13
 
@@ -45,6 +49,8 @@ SFI has mature, well-tested abstractions for every common operation.
45
49
  | Wrap a user function as a state function | `SFI.statefunc.make_basis` / `make_sf` / `make_psf` |
46
50
  | Run force / diffusion inference | `SFI.OverdampedLangevinInference` / `UnderdampedLangevinInference` |
47
51
  | Select a sparse model | `inf.sparsify_force(criterion="PASTIS", p=0.1)` |
52
+ | Select a sparse diffusion model | `inf.sparsify_diffusion(criterion="PASTIS", p=0.05)` |
53
+ | Keep terms in every model / select grouped terms together | `inf.sparsify_force(protected=[...], groups={...})` (indices or `basis.labels`; also `sparsify_diffusion`) |
48
54
  | Compare to ground truth | `inf.compare_to_exact(model_exact=...)` |
49
55
  | Plot in the SFI style | `SFI.utils.plotting.SFI_COLORS`, `dark_fig`, `phase2d` |
50
56
  | Save / load a fitted model | `SFI.inference.save_model` / `load_model` |
@@ -78,6 +84,37 @@ from SFI import (
78
84
  The dynamics-order classifier (`classify_dynamics`, returning a
79
85
  `DynamicsOrderReport`) decides overdamped vs underdamped from raw
80
86
  positions; see `SFI.diagnostics` and `examples/gallery/dynamics_order_demo.py`.
87
+ `SFI.diagnostics.finite_dt_scale(inf)` reports the per-step drift-gradient
88
+ scale Δt‖∇F̂‖ of a fitted force (the size of the linear estimators' O(Δt)
89
+ biases) with a `fine` / `coarse` / `unreliable` verdict; `assess(inf)` includes
90
+ it and flags the coarse regimes. For underdamped linear fits with the default
91
+ constant diffusion, `assess(inf)` also compares it with the drift-corrected one
92
+ (`report.diffusion`: difference, z, chi-squared p-value; one pass with the fitted
93
+ force), the check `compute_diffusion_constant(method="drift-corrected")` runs and
94
+ stores when it replaces the default. Both linear engines also record the force
95
+ Gram condition number (`metadata["force_gram_cond"]`) and warn when the
96
+ dictionary is ill-conditioned on the data; the underdamped linear
97
+ estimators also warn on non-uniform frame intervals
98
+ (`metadata["dt_mismatch_rms"]`), which they do not support. After an
99
+ underdamped linear fit, `compute_force_error()` also checks the basis's
100
+ path resolution (`metadata["force_path_resolution"]`: features that vary
101
+ along the motion within a stencil, their attenuation `kappa` and predicted
102
+ bias in error bars; it warns when a bias exceeds its error bar). Under
103
+ strong localisation noise at fine sampling (`metadata["force_noise_ratio"]`
104
+ >= 1, warned), fit with `infer_force_linear(B, stride="auto")` (experimental)
105
+ (`preset="model-free"` / `"constant-noise"`): it picks the frame stride
106
+ (`metadata["force_stride_scan"]`). Estimate the diffusion constant the same
107
+ way, `compute_diffusion_constant(stride="auto")`
108
+ (`metadata["diffusion_constant_stride_scan"]`): at stride 1 its sign is
109
+ random once the noise ratio exceeds about sqrt(rows), and the force fit
110
+ needs a positive definite constant. The diffusion field likewise:
111
+ `infer_diffusion_linear(B_D, stride="auto")`
112
+ (`metadata["diffusion_stride_scan"]`). A selected stride above 1 warns with
113
+ its reason.
114
+ `SFI.diagnostics.psd_fraction(D_sf, coll)` reports the fraction of data
115
+ points where a diffusion field is not positive semi-definite;
116
+ `simulate_bootstrapped_trajectory` runs it on the fitted diffusion and warns
117
+ (the simulator clips negative eigenvalues silently).
81
118
 
82
119
  ### 4.2 `SFI.statefunc` — composable state functions
83
120
 
@@ -89,7 +126,7 @@ positions; see `SFI.diagnostics` and `examples/gallery/dynamics_order_demo.py`.
89
126
  | `make_sf(func, dim, rank, ...)` | Wrap a Python callable as an `SF` |
90
127
  | `make_psf(func, dim, rank, ...)` | Wrap a callable with parameters as `PSF` |
91
128
  | `make_basis(func, dim, ...)` | Wrap a vector-valued callable as `Basis` |
92
- | `Interactor`, `make_interactor` | Multi-scale interaction graphs |
129
+ | `Interactor`, `make_interactor` | Multi-scale interaction graphs (pairs, hyperedges; `per_slot=True` for many-body forces) |
93
130
 
94
131
  ### 4.3 `SFI.inference` — inference engines
95
132
 
@@ -134,7 +171,7 @@ agreement is itself a diagnostic.
134
171
  | `inf.print_report()` / `inf.report_dict()` | Human / machine summary |
135
172
  | `inf.compare_to_exact(model_exact=...)` | Validate against a known model |
136
173
  | `inf.holdout_score(test)` | Held-out NMSE on `coll.split_time(...)` test data (data-abundant scenarios only) |
137
- | `inf.compute_entropy_production()` | Dissipation of the observed dynamics (after a linear force fit; both engines): rate ± error + fluctuation bias and the AIC-debiased rate (`Sdot_debiased`), in k_B. Underdamped: positions-only via the even/odd split; `coefficients=` enables cross-fitting |
174
+ | `inf.compute_entropy_production()` | Dissipation of the observed dynamics (after a linear force fit; both engines): rate ± error + fluctuation bias and the AIC-debiased rate (`Sdot_debiased`), in k_B. Underdamped: positions-only via the even/odd split; `coefficients=` enables cross-fitting, `jackknife=True` the delete-half jackknife (`Sdot_jackknife`, free of the plug-in bias) |
138
175
  | `inf.time_reversal_split()` | Underdamped only: the fitted field's reversible/irreversible parts `(F_even, F_odd)` as callables |
139
176
 
140
177
  * **Parametric estimators (robust, flexible; compute-intensive).**
@@ -179,14 +216,14 @@ agreement is itself a diagnostic.
179
216
 
180
217
  ```python
181
218
  inf = OverdampedLangevinInference(collection)
182
- inf.compute_diffusion_constant(method="auto") # 1. constant D ("noisy"/"WeakNoise"/"MSD")
183
- inf.infer_force_linear(basis, preset="auto") # 2. force ("auto"/"robust"/"clean"/"KM"/legacy)
184
- inf.infer_diffusion_linear() # 3. optional: constant sym D (default basis)
185
- inf.compute_force_error() # 4. error analysis
186
- inf.sparsify_force(criterion="PASTIS", p=0.1) # 5. optional: sparsity
187
- inf.compute_entropy_production() # 6. optional: dissipation (OD & UD)
188
- inf.print_report() # 7. summary
189
- inf.compare_to_exact(model_exact=process) # 8. optional: validate
219
+ inf.infer_force_linear(basis) # 1. force (overdamped preset "instrument" default/"legacy-robust"/"legacy-clean"/"legacy-KM"/"legacy-noisy-v1.0", "auto" retired: fit it FIRST, it sets the drift-corrected constant D-bar and Lambda; underdamped "model-free" default/"constant-noise"/"legacy-robust"/"legacy-clean"/legacy v1.0, after compute_diffusion_constant())
220
+ # constant D otherwise: overdamped compute_diffusion_constant() (default "noisy"; "WeakNoise"/"MSD" by name) only to keep a stencil D (a prior call keeps it), method="drift-corrected" after step 1; underdamped compute_diffusion_constant() before step 1 (default "model-free", legacy stencils by name, "drift-corrected" after step 1)
221
+ inf.infer_diffusion_linear() # 2. optional: diffusion field (overdamped: basis optional, default = constant sym D; default "drift-corrected" = regressed on the force's residuals, needs step 1; underdamped: basis required, default "model-free", "drift-corrected" after step 1; M_mode= selects the legacy fit in both)
222
+ inf.compute_force_error() # 3. error analysis
223
+ inf.sparsify_force(criterion="PASTIS", p=0.1) # 4. optional: sparsity
224
+ inf.compute_entropy_production() # 5. optional: dissipation (OD & UD)
225
+ inf.print_report() # 6. summary
226
+ inf.compare_to_exact(model_exact=process) # 7. optional: validate
190
227
  ```
191
228
 
192
229
  **Parametric-estimator sequence:**
@@ -200,10 +237,19 @@ inf.compute_force_error()
200
237
 
201
238
  **Sparsity.** PASTIS is the canonical criterion in SFI. Alternative
202
239
  criteria (`AIC`, `BIC`, `SIC`) and strategies (greedy stepwise,
203
- STLSQ, LASSO) are available — see
240
+ STLSQ, LASSO, `method="exhaustive"` for the exact front of small
241
+ candidate sets) are available — see
204
242
  [`_project_index/api_map.md`](_project_index/api_map.md#sfiinferencesparse)
205
243
  for the full inventory. Precision/recall and held-out NMSE helpers
206
244
  live in `SFI.inference.sparse.overlap_metrics` and `predictive_nmse`.
245
+ `protected=` keeps functions in every model (not candidates: nuisance
246
+ blocks, a required friction) and `groups=` makes functions enter and
247
+ leave together (a harmonic's `(cos, sin)` pair, per-dataset copies); the
248
+ search then runs over units (`UnitScorer`), `k`/`max_k` count units, and
249
+ PASTIS charges a group of `m` parameters `pastis_unit_penalty(m, n0, p)`
250
+ (the exact chi-squared quantile at a single term's false-inclusion level;
251
+ `ln(n0/p)` for `m = 1`). `SparsityResult.selected()` returns the chosen
252
+ model with its information, parameter count and unit names.
207
253
 
208
254
  ### 4.4 `SFI.trajectory` — data containers
209
255
 
@@ -354,6 +400,21 @@ Deprecated / soon-to-be-removed symbols (do not use in new code):
354
400
  deprecated tuning knobs, accepted but **inert** (a
355
401
  `DeprecationWarning` fires when set). The banded likelihood has no
356
402
  window truncation to tune.
403
+ - Underdamped `infer_force_linear(preset="auto" | "robust" | "clean")` —
404
+ retired names, accepted with a `FutureWarning`: `"auto"` runs the
405
+ default `"model-free"` (combined with explicit `M_mode` / `G_mode` /
406
+ `diffusion_method` / `cross_particle` it raises: name a `legacy-` preset); `"robust"` / `"clean"` are
407
+ now `"legacy-robust"` / `"legacy-clean"`. Mode overrides apply to the
408
+ `legacy-` presets only; without a preset they warn and will raise.
409
+ - Underdamped `compute_diffusion_constant(method="auto")` — retired, accepted
410
+ with a `FutureWarning`: runs the default `"model-free"` (the mean of the
411
+ model-free force design's per-frame diffusion). The former choice
412
+ (`"noisy"` when `Tr Lambda > 0`, else `"WeakNoise"`) is available by name.
413
+ - Overdamped `infer_force_linear(preset="auto")` — retired, accepted with a
414
+ `FutureWarning`: runs the default `"instrument"`. Its former choice
415
+ (`"robust"` when `Tr Lambda > 0`, else `"clean"`) is available by name;
416
+ mode arguments without a preset are still completed that way
417
+ (`SharedNoiseOLI` keeps that choice as its default).
357
418
 
358
419
  ## 6. Testing, building, environment
359
420
 
@@ -363,6 +424,7 @@ Full details: [`docs/source/dev_notes.rst`](docs/source/dev_notes.rst).
363
424
  source .venv/bin/activate
364
425
  pytest tests/ -v # full suite (CPU-only via conftest)
365
426
  pytest tests/ -x --ff # quick smoke
427
+ pytest tests/inference -m sparsity # when changing sparse selection (deselected by default)
366
428
  cd docs && make clean && make html # fast docs build
367
429
  cd docs && SFI_DOCS_RUN_GALLERY=1 make html # full build (slow)
368
430
  ```
@@ -4,6 +4,7 @@ recursive-include examples *.py
4
4
  # Top-level docs we want shipped
5
5
  include README.md LICENSE pyproject.toml setup.cfg
6
6
  include AGENTS.md CONTRIBUTING.md GALLERY_STYLE_GUIDE.md
7
+ include SFI/AGENT_GUIDE.md
7
8
 
8
9
  # Exclude common junk files
9
10
  global-exclude *.csv *.mp4 *.pkl *.npz *.npy *~ *.bak
@@ -1,15 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: StochasticForceInference
3
- Version: 2.0.3
4
- Summary: Stochastic Force Inference for Langevin SDEs
3
+ Version: 2.1.0
4
+ Summary: Learn stochastic differential equations (Langevin dynamics: drift/force and diffusion) from time series and trajectory data
5
5
  Author-email: Pierre Ronceray <pierre.ronceray@univ-amu.fr>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/ronceray/StochasticForceInference
8
8
  Project-URL: Documentation, https://stochasticforceinference.readthedocs.io
9
+ Project-URL: Gallery, https://stochasticforceinference.readthedocs.io/en/stable/gallery/index.html
10
+ Project-URL: Guide for AI agents, https://github.com/ronceray/StochasticForceInference/blob/main/SFI/AGENT_GUIDE.md
9
11
  Project-URL: Repository, https://github.com/ronceray/StochasticForceInference
10
12
  Project-URL: Issues, https://github.com/ronceray/StochasticForceInference/issues
11
13
  Project-URL: Changelog, https://github.com/ronceray/StochasticForceInference/blob/main/CHANGELOG.md
12
- Keywords: stochastic force inference,Langevin dynamics,stochastic differential equations,diffusion,inference,sparse model selection,active matter,biophysics,JAX
14
+ Keywords: stochastic force inference,Langevin dynamics,stochastic differential equations,SDE,diffusion,inference,drift estimation,diffusion estimation,Kramers-Moyal,Fokker-Planck,time series,trajectory analysis,system identification,equation discovery,sparse model selection,particle tracking,single-particle tracking,cell migration,population dynamics,gene expression,entropy production,Ornstein-Uhlenbeck,active matter,biophysics,JAX
13
15
  Classifier: Development Status :: 5 - Production/Stable
14
16
  Classifier: Intended Audience :: Science/Research
15
17
  Classifier: License :: OSI Approved :: MIT License
@@ -20,13 +22,14 @@ Classifier: Programming Language :: Python :: 3.12
20
22
  Classifier: Programming Language :: Python :: 3.13
21
23
  Classifier: Topic :: Scientific/Engineering :: Physics
22
24
  Classifier: Topic :: Scientific/Engineering :: Mathematics
25
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
23
26
  Requires-Python: >=3.11
24
27
  Description-Content-Type: text/markdown
25
28
  License-File: LICENSE
26
29
  Requires-Dist: numpy
27
30
  Requires-Dist: scipy
28
- Requires-Dist: jax>=0.10
29
- Requires-Dist: jaxlib
31
+ Requires-Dist: jax!=0.10.2,!=0.11.0,>=0.10.1
32
+ Requires-Dist: jaxlib!=0.10.2,!=0.11.0,>=0.10.1
30
33
  Requires-Dist: pandas
31
34
  Requires-Dist: matplotlib
32
35
  Requires-Dist: pyyaml
@@ -42,6 +45,7 @@ Requires-Dist: sphinxcontrib-video; extra == "docs"
42
45
  Requires-Dist: sphinxcontrib-mermaid; extra == "docs"
43
46
  Provides-Extra: dev
44
47
  Requires-Dist: pytest; extra == "dev"
48
+ Requires-Dist: pytest-xdist; extra == "dev"
45
49
  Requires-Dist: ruff; extra == "dev"
46
50
  Requires-Dist: pyright; extra == "dev"
47
51
  Requires-Dist: StochasticForceInference[docs]; extra == "dev"
@@ -57,14 +61,38 @@ Dynamic: license-file
57
61
  [![Documentation](https://readthedocs.org/projects/stochasticforceinference/badge/?version=latest)](https://stochasticforceinference.readthedocs.io/en/latest/)
58
62
  [![PyPI](https://img.shields.io/pypi/v/StochasticForceInference.svg)](https://pypi.org/project/StochasticForceInference/)
59
63
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/ronceray/StochasticForceInference/blob/main/LICENSE)
60
-
61
- **Infer force and diffusion fields from stochastic trajectory data.**
62
-
63
- SFI is a JAX-based Python package for learning the drift (force) and diffusion
64
- of Langevin stochastic differential equations from time-series observations.
65
- It handles both overdamped and underdamped dynamics, supports interacting
66
- particles and spatially-extended (SPDE) systems, and provides built-in
67
- diagnostics, sparse model selection, and bootstrapped validation.
64
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21532842.svg)](https://doi.org/10.5281/zenodo.21532842)
65
+
66
+ **Learn the stochastic equation behind your time series.**
67
+
68
+ SFI is a JAX-based Python package that infers the drift (force) and
69
+ diffusion of Langevin stochastic differential equations from trajectories
70
+ and other continuous time series: tracked particles, cells and animals,
71
+ population abundances, gene-expression and other molecular levels,
72
+ concentration fields. It returns an interpretable
73
+ equation with error bars, selects the terms the data supports, and
74
+ simulates the fitted model. It handles overdamped and underdamped
75
+ dynamics, interacting particles and spatially extended (SPDE) systems.
76
+
77
+ ## Is SFI for my data?
78
+
79
+ | You want to… | SFI does it with |
80
+ | --- | --- |
81
+ | estimate drift and diffusion (first and second Kramers–Moyal coefficients, a Fokker–Planck model) | `OverdampedLangevinInference`: `infer_force_linear`, `infer_diffusion_linear` |
82
+ | discover the equation of a noisy stochastic system (sparse regression, "stochastic SINDy") | a candidate basis + `sparsify_force(criterion="PASTIS")` |
83
+ | map forces and diffusivity from single-particle tracking, with localization error | the overdamped engine; the defaults correct white localization noise |
84
+ | model cell migration, animal movement or active particles (persistent velocities) | `UnderdampedLangevinInference`, from positions alone |
85
+ | measure interaction forces between particles, collective motion | pair bases (`SFI.bases.pairs`) |
86
+ | model population dynamics: microbial or ecological abundances, growth rates, species interactions | the overdamped engine on log-abundances + `sparsify_force` ([Lotka–Volterra example](https://stochasticforceinference.readthedocs.io/en/stable/gallery/lotka_volterra_demo.html)) |
87
+ | model gene-expression, protein or metabolite levels, whose noise scales with the level | the overdamped engine with a diffusion field `D(x)` (`infer_diffusion_linear`) |
88
+ | fit noisy oscillators and chaotic signals (genetic or circadian clocks, hair bundles) | a nonlinear basis; `UnderdampedLangevinInference` when one coordinate of an inertial oscillator is observed |
89
+ | quantify irreversibility: entropy production, broken detailed balance | `compute_entropy_production()` |
90
+ | decide whether the dynamics are overdamped or underdamped | `SFI.classify_dynamics` |
91
+
92
+ SFI is not the right tool for categorical data, small counts or events, for
93
+ forecasting without an equation, for snapshots without time correlation,
94
+ or for processes with jumps. More routes:
95
+ [Start here](https://stochasticforceinference.readthedocs.io/en/stable/start_here.html).
68
96
 
69
97
  > **Designed for experimental data.** SFI is built for real experimental
70
98
  > trajectories (tracked particles, cells, organisms, …) where *no dynamical
@@ -78,10 +106,11 @@ diagnostics, sparse model selection, and bootstrapped validation.
78
106
  ## Key features
79
107
 
80
108
  - **Two estimator families** — closed-form linear estimators
81
- (`infer_force_linear`, seconds even on large datasets) and parametric
82
- estimators (`infer_force` / `infer_diffusion`: noise-aware likelihood
83
- fit, robust to localization error and coarse sampling, accepts
84
- nonlinear models such as neural-network drifts).
109
+ (`infer_force_linear`, seconds even on large datasets; the defaults
110
+ correct localization noise and the leading finite-time-step bias) and
111
+ parametric estimators (`infer_force` / `infer_diffusion`: noise-aware
112
+ likelihood fit, robust to localization error and coarse sampling,
113
+ accepts nonlinear models such as neural-network drifts).
85
114
  - **Overdamped & underdamped inference** — works with position-only data;
86
115
  velocities are reconstructed automatically for underdamped systems.
87
116
  - **Composable state functions** — build force/diffusion models from
@@ -89,18 +118,21 @@ diagnostics, sparse model selection, and bootstrapped validation.
89
118
  parametric families, all with automatic differentiation via JAX.
90
119
  - **Sparse model selection** — Pareto-front beam search with AIC / BIC /
91
120
  PASTIS information criteria.
92
- - **Simulation** — simulate Langevin SDEs (Euler–Maruyama) from the same
93
- model objects used for inference.
121
+ - **Entropy production** — dissipation rate with error bar, for
122
+ overdamped and underdamped dynamics.
123
+ - **Simulation** — simulate Langevin SDEs from the same model objects
124
+ used for inference, including bootstrapped trajectories of a fitted model.
94
125
  - **Trajectory toolkit** — mask-aware increments, synthetic degradation
95
126
  (noise, downsampling, data loss, motion blur), streaming for large
96
- datasets, I/O (CSV / Parquet / HDF5).
97
- - **Diagnostics** — compare inferred fields to exact models, compute
98
- normalized errors, generate bootstrapped trajectories.
127
+ datasets, I/O (CSV / Parquet / HDF5, tracking tables).
128
+ - **Diagnostics** — residual tests with action hints, an
129
+ overdamped-vs-underdamped classifier, predicted errors, comparison to
130
+ exact models.
99
131
 
100
132
  ## Installation
101
133
 
102
134
  ```bash
103
- pip install StochasticForceInference
135
+ pip install StochasticForceInference # import name: SFI
104
136
  ```
105
137
 
106
138
  For development (editable install with test/doc dependencies):
@@ -129,12 +161,13 @@ coll = TrajectoryCollection.from_arrays(X=positions, dt=0.01)
129
161
  # Infer using a polynomial basis — no model needed
130
162
  B = monomials_up_to(order=3, dim=2, rank="vector")
131
163
  inf = OverdampedLangevinInference(coll)
132
- inf.compute_diffusion_constant()
133
- inf.infer_force_linear(B)
164
+ inf.infer_force_linear(B) # also estimates D and the measurement noise
134
165
  inf.sparsify_force(criterion="PASTIS") # optional: find the minimal model
135
- inf.print_report()
166
+ inf.compute_force_error()
167
+ inf.print_report() # coefficients with error bars
168
+ inf.diagnose().print_summary() # residual tests, with hints if one fails
136
169
 
137
- # Noisy or coarsely-sampled recordings? Use the parametric estimator
170
+ # Coarsely sampled or very noisy recordings? Use the parametric estimator
138
171
  # instead: inf.infer_force(B) — it models the measurement noise natively.
139
172
  ```
140
173
 
@@ -157,7 +190,6 @@ coll = proc.simulate(dt=0.01, Nsteps=10_000, key=random.PRNGKey(0))
157
190
  # 2. Infer from the trajectory using a generic polynomial basis
158
191
  B = monomials_up_to(order=2, dim=2, rank="vector")
159
192
  inf = OverdampedLangevinInference(coll)
160
- inf.compute_diffusion_constant()
161
193
  inf.infer_force_linear(B)
162
194
  inf.compute_force_error()
163
195
 
@@ -166,11 +198,35 @@ inf.print_report()
166
198
  inf.compare_to_exact(model_exact=proc)
167
199
  ```
168
200
 
201
+ ## Using SFI with an AI agent
202
+
203
+ SFI ships a workflow guide for AI coding agents (Claude Code, Codex,
204
+ Cursor, …) inside the package, matched to the installed version:
205
+
206
+ ```bash
207
+ python -m SFI guide # Markdown: workflow, decisions, pitfalls, API names
208
+
209
+ # Install it as an Agent Skill (path shown for Claude Code; other tools that support skills use their own folder)
210
+ mkdir -p ~/.claude/skills/stochastic-force-inference
211
+ python -m SFI guide --skill > ~/.claude/skills/stochastic-force-inference/SKILL.md
212
+ ```
213
+
214
+ The documentation has an [`llms.txt`](https://stochasticforceinference.readthedocs.io/llms.txt)
215
+ index. Agents that modify SFI itself should read
216
+ [`AGENTS.md`](https://github.com/ronceray/StochasticForceInference/blob/main/AGENTS.md).
217
+
218
+ **Coming from the original SFI scripts** (`StochasticForceInference.py`,
219
+ `StochasticTrajectoryData`, or the separate UnderdampedLangevinInference
220
+ package)? SFI 2 is a rewrite with a new API; the
221
+ [guide](https://github.com/ronceray/StochasticForceInference/blob/main/SFI/AGENT_GUIDE.md#9-coming-from-the-original-sfi-scripts-or-older-example-code)
222
+ maps the old calls to the new ones.
223
+
169
224
  ## Documentation
170
225
 
171
226
  Full documentation is available at
172
227
  [stochasticforceinference.readthedocs.io](https://stochasticforceinference.readthedocs.io), including:
173
228
 
229
+ - **[Start here](https://stochasticforceinference.readthedocs.io/en/latest/start_here.html)** — is SFI right for my data, and which route to take
174
230
  - **[Tutorial](https://stochasticforceinference.readthedocs.io/en/latest/gallery/ou_demo.html)** — end-to-end walkthrough
175
231
  - **[Examples gallery](https://stochasticforceinference.readthedocs.io/en/latest/gallery/index.html)** — worked examples covering sparsity, multi-particle, and SPDE inference
176
232
  - **[Model building](https://stochasticforceinference.readthedocs.io/en/latest/statefunc/user_guide.html)** — composable state functions
@@ -180,25 +236,28 @@ Full documentation is available at
180
236
 
181
237
  ## Package structure
182
238
 
183
- | Subpackage | Purpose |
184
- | ---------------- | ---------------------------------------------------- |
185
- | `SFI.statefunc` | Composable state functions: `Basis`, `PSF`, `SF` |
186
- | `SFI.inference` | Overdamped & underdamped inference engines |
187
- | `SFI.trajectory` | `TrajectoryCollection` / `TrajectoryDataset` |
188
- | `SFI.langevin` | Langevin simulators (`OverdampedProcess`, …) |
189
- | `SFI.bases` | Ready-made basis builders (monomials, constants, …) |
190
- | `SFI.integrate` | Time-averaging integration engine |
191
- | `SFI.utils` | Math helpers, formatting, plotting |
192
-
193
- For contributors and AI coding agents: see [`AGENTS.md`](https://github.com/ronceray/StochasticForceInference/blob/main/AGENTS.md) for
194
- the canonical imports table, task playbooks, and "do not re-implement"
195
- guidance.
239
+ | Subpackage | Purpose |
240
+ | ----------------- | ---------------------------------------------------- |
241
+ | `SFI.statefunc` | Composable state functions: `Basis`, `PSF`, `SF` |
242
+ | `SFI.inference` | Overdamped & underdamped inference engines |
243
+ | `SFI.trajectory` | `TrajectoryCollection` / `TrajectoryDataset` |
244
+ | `SFI.langevin` | Langevin simulators (`OverdampedProcess`, …) |
245
+ | `SFI.bases` | Ready-made basis builders (monomials, pairs, SPDE, …) |
246
+ | `SFI.diagnostics` | Residual tests, dynamics classifier, error checks |
247
+ | `SFI.integrate` | Time-averaging integration engine |
248
+ | `SFI.utils` | Math helpers, formatting, plotting |
196
249
 
197
250
  ## Citation
198
251
 
199
- If you use SFI, please cite the software (see [`CITATION.cff`](CITATION.cff))
200
- together with the method paper(s) relevant to the features you use. See
201
- **[How to cite](https://stochasticforceinference.readthedocs.io/en/latest/#how-to-cite)** in the
252
+ If you use SFI, please cite the software (see [`CITATION.cff`](https://github.com/ronceray/StochasticForceInference/blob/main/CITATION.cff))
253
+ together with the method paper(s) relevant to the features you use.
254
+
255
+ The software is archived on Zenodo. Cite the concept DOI
256
+ [10.5281/zenodo.21532842](https://doi.org/10.5281/zenodo.21532842), which always
257
+ resolves to the latest release; each version also has its own DOI (v2.0.4:
258
+ [10.5281/zenodo.23498743](https://doi.org/10.5281/zenodo.23498743)).
259
+
260
+ See **[How to cite](https://stochasticforceinference.readthedocs.io/en/latest/#how-to-cite)** in the
202
261
  documentation for the full, feature-specific list (overdamped, underdamped/ULI,
203
262
  trapeze, and PASTIS references).
204
263
 
@@ -0,0 +1,218 @@
1
+ # Stochastic Force Inference (SFI)
2
+
3
+ [![Documentation](https://readthedocs.org/projects/stochasticforceinference/badge/?version=latest)](https://stochasticforceinference.readthedocs.io/en/latest/)
4
+ [![PyPI](https://img.shields.io/pypi/v/StochasticForceInference.svg)](https://pypi.org/project/StochasticForceInference/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/ronceray/StochasticForceInference/blob/main/LICENSE)
6
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21532842.svg)](https://doi.org/10.5281/zenodo.21532842)
7
+
8
+ **Learn the stochastic equation behind your time series.**
9
+
10
+ SFI is a JAX-based Python package that infers the drift (force) and
11
+ diffusion of Langevin stochastic differential equations from trajectories
12
+ and other continuous time series: tracked particles, cells and animals,
13
+ population abundances, gene-expression and other molecular levels,
14
+ concentration fields. It returns an interpretable
15
+ equation with error bars, selects the terms the data supports, and
16
+ simulates the fitted model. It handles overdamped and underdamped
17
+ dynamics, interacting particles and spatially extended (SPDE) systems.
18
+
19
+ ## Is SFI for my data?
20
+
21
+ | You want to… | SFI does it with |
22
+ | --- | --- |
23
+ | estimate drift and diffusion (first and second Kramers–Moyal coefficients, a Fokker–Planck model) | `OverdampedLangevinInference`: `infer_force_linear`, `infer_diffusion_linear` |
24
+ | discover the equation of a noisy stochastic system (sparse regression, "stochastic SINDy") | a candidate basis + `sparsify_force(criterion="PASTIS")` |
25
+ | map forces and diffusivity from single-particle tracking, with localization error | the overdamped engine; the defaults correct white localization noise |
26
+ | model cell migration, animal movement or active particles (persistent velocities) | `UnderdampedLangevinInference`, from positions alone |
27
+ | measure interaction forces between particles, collective motion | pair bases (`SFI.bases.pairs`) |
28
+ | model population dynamics: microbial or ecological abundances, growth rates, species interactions | the overdamped engine on log-abundances + `sparsify_force` ([Lotka–Volterra example](https://stochasticforceinference.readthedocs.io/en/stable/gallery/lotka_volterra_demo.html)) |
29
+ | model gene-expression, protein or metabolite levels, whose noise scales with the level | the overdamped engine with a diffusion field `D(x)` (`infer_diffusion_linear`) |
30
+ | fit noisy oscillators and chaotic signals (genetic or circadian clocks, hair bundles) | a nonlinear basis; `UnderdampedLangevinInference` when one coordinate of an inertial oscillator is observed |
31
+ | quantify irreversibility: entropy production, broken detailed balance | `compute_entropy_production()` |
32
+ | decide whether the dynamics are overdamped or underdamped | `SFI.classify_dynamics` |
33
+
34
+ SFI is not the right tool for categorical data, small counts or events, for
35
+ forecasting without an equation, for snapshots without time correlation,
36
+ or for processes with jumps. More routes:
37
+ [Start here](https://stochasticforceinference.readthedocs.io/en/stable/start_here.html).
38
+
39
+ > **Designed for experimental data.** SFI is built for real experimental
40
+ > trajectories (tracked particles, cells, organisms, …) where *no dynamical
41
+ > model pre-exists*. Two first-class estimator families share one API:
42
+ > fast closed-form **linear estimators** that require no initial guess, and
43
+ > **parametric estimators** that model measurement noise and finite sampling
44
+ > explicitly — robust where real data is hard. The PASTIS information
45
+ > criterion rigorously identifies which terms the data actually supports.
46
+ > Synthetic examples in the gallery serve as runnable demonstrations.
47
+
48
+ ## Key features
49
+
50
+ - **Two estimator families** — closed-form linear estimators
51
+ (`infer_force_linear`, seconds even on large datasets; the defaults
52
+ correct localization noise and the leading finite-time-step bias) and
53
+ parametric estimators (`infer_force` / `infer_diffusion`: noise-aware
54
+ likelihood fit, robust to localization error and coarse sampling,
55
+ accepts nonlinear models such as neural-network drifts).
56
+ - **Overdamped & underdamped inference** — works with position-only data;
57
+ velocities are reconstructed automatically for underdamped systems.
58
+ - **Composable state functions** — build force/diffusion models from
59
+ monomials, custom basis functions, pair interactions, or arbitrary
60
+ parametric families, all with automatic differentiation via JAX.
61
+ - **Sparse model selection** — Pareto-front beam search with AIC / BIC /
62
+ PASTIS information criteria.
63
+ - **Entropy production** — dissipation rate with error bar, for
64
+ overdamped and underdamped dynamics.
65
+ - **Simulation** — simulate Langevin SDEs from the same model objects
66
+ used for inference, including bootstrapped trajectories of a fitted model.
67
+ - **Trajectory toolkit** — mask-aware increments, synthetic degradation
68
+ (noise, downsampling, data loss, motion blur), streaming for large
69
+ datasets, I/O (CSV / Parquet / HDF5, tracking tables).
70
+ - **Diagnostics** — residual tests with action hints, an
71
+ overdamped-vs-underdamped classifier, predicted errors, comparison to
72
+ exact models.
73
+
74
+ ## Installation
75
+
76
+ ```bash
77
+ pip install StochasticForceInference # import name: SFI
78
+ ```
79
+
80
+ For development (editable install with test/doc dependencies):
81
+
82
+ ```bash
83
+ git clone https://github.com/ronceray/StochasticForceInference.git
84
+ cd StochasticForceInference
85
+ pip install -e ".[dev,io]"
86
+ ```
87
+
88
+ > **Note:** SFI requires Python ≥ 3.11 and JAX ≥ 0.10.
89
+
90
+ ## Quick start
91
+
92
+ For **experimental data**, load your trajectories and infer directly:
93
+
94
+ ```python
95
+ import numpy as np
96
+ from SFI import OverdampedLangevinInference, TrajectoryCollection
97
+ from SFI.bases import monomials_up_to
98
+
99
+ # Load your tracked data (positions: T×d array, dt: time step)
100
+ positions = np.load("my_experiment.npz")["positions"] # shape (T, d)
101
+ coll = TrajectoryCollection.from_arrays(X=positions, dt=0.01)
102
+
103
+ # Infer using a polynomial basis — no model needed
104
+ B = monomials_up_to(order=3, dim=2, rank="vector")
105
+ inf = OverdampedLangevinInference(coll)
106
+ inf.infer_force_linear(B) # also estimates D and the measurement noise
107
+ inf.sparsify_force(criterion="PASTIS") # optional: find the minimal model
108
+ inf.compute_force_error()
109
+ inf.print_report() # coefficients with error bars
110
+ inf.diagnose().print_summary() # residual tests, with hints if one fails
111
+
112
+ # Coarsely sampled or very noisy recordings? Use the parametric estimator
113
+ # instead: inf.infer_force(B) — it models the measurement noise natively.
114
+ ```
115
+
116
+ For a **synthetic example** (useful for validation):
117
+
118
+ ```python
119
+ import jax.numpy as jnp
120
+ from jax import random
121
+
122
+ from SFI import OverdampedLangevinInference
123
+ from SFI.bases import X, monomials_up_to
124
+ from SFI.langevin import OverdampedProcess
125
+
126
+ # 1. Build a force model (Ornstein–Uhlenbeck: F = -k x) and simulate a trajectory.
127
+ # X(dim) is the identity basis x ↦ x; theta_F holds its coefficient, so F(x) = -x.
128
+ proc = OverdampedProcess(F=X(dim=2), D=jnp.eye(2) * 0.5, theta_F=jnp.array([-1.0]))
129
+ proc.initialize(jnp.zeros(2))
130
+ coll = proc.simulate(dt=0.01, Nsteps=10_000, key=random.PRNGKey(0))
131
+
132
+ # 2. Infer from the trajectory using a generic polynomial basis
133
+ B = monomials_up_to(order=2, dim=2, rank="vector")
134
+ inf = OverdampedLangevinInference(coll)
135
+ inf.infer_force_linear(B)
136
+ inf.compute_force_error()
137
+
138
+ # 3. Inspect results and validate against the known model
139
+ inf.print_report()
140
+ inf.compare_to_exact(model_exact=proc)
141
+ ```
142
+
143
+ ## Using SFI with an AI agent
144
+
145
+ SFI ships a workflow guide for AI coding agents (Claude Code, Codex,
146
+ Cursor, …) inside the package, matched to the installed version:
147
+
148
+ ```bash
149
+ python -m SFI guide # Markdown: workflow, decisions, pitfalls, API names
150
+
151
+ # Install it as an Agent Skill (path shown for Claude Code; other tools that support skills use their own folder)
152
+ mkdir -p ~/.claude/skills/stochastic-force-inference
153
+ python -m SFI guide --skill > ~/.claude/skills/stochastic-force-inference/SKILL.md
154
+ ```
155
+
156
+ The documentation has an [`llms.txt`](https://stochasticforceinference.readthedocs.io/llms.txt)
157
+ index. Agents that modify SFI itself should read
158
+ [`AGENTS.md`](https://github.com/ronceray/StochasticForceInference/blob/main/AGENTS.md).
159
+
160
+ **Coming from the original SFI scripts** (`StochasticForceInference.py`,
161
+ `StochasticTrajectoryData`, or the separate UnderdampedLangevinInference
162
+ package)? SFI 2 is a rewrite with a new API; the
163
+ [guide](https://github.com/ronceray/StochasticForceInference/blob/main/SFI/AGENT_GUIDE.md#9-coming-from-the-original-sfi-scripts-or-older-example-code)
164
+ maps the old calls to the new ones.
165
+
166
+ ## Documentation
167
+
168
+ Full documentation is available at
169
+ [stochasticforceinference.readthedocs.io](https://stochasticforceinference.readthedocs.io), including:
170
+
171
+ - **[Start here](https://stochasticforceinference.readthedocs.io/en/latest/start_here.html)** — is SFI right for my data, and which route to take
172
+ - **[Tutorial](https://stochasticforceinference.readthedocs.io/en/latest/gallery/ou_demo.html)** — end-to-end walkthrough
173
+ - **[Examples gallery](https://stochasticforceinference.readthedocs.io/en/latest/gallery/index.html)** — worked examples covering sparsity, multi-particle, and SPDE inference
174
+ - **[Model building](https://stochasticforceinference.readthedocs.io/en/latest/statefunc/user_guide.html)** — composable state functions
175
+ - **[Trajectory handling](https://stochasticforceinference.readthedocs.io/en/latest/trajectory/user_guide.html)** — data ingestion, masking, degradation
176
+ - **[Running inference](https://stochasticforceinference.readthedocs.io/en/latest/inference/user_guide.html)** — estimator choice, overdamped/underdamped engines
177
+ - **[API reference](https://stochasticforceinference.readthedocs.io/en/latest/api_frontend.html)** — full autodoc
178
+
179
+ ## Package structure
180
+
181
+ | Subpackage | Purpose |
182
+ | ----------------- | ---------------------------------------------------- |
183
+ | `SFI.statefunc` | Composable state functions: `Basis`, `PSF`, `SF` |
184
+ | `SFI.inference` | Overdamped & underdamped inference engines |
185
+ | `SFI.trajectory` | `TrajectoryCollection` / `TrajectoryDataset` |
186
+ | `SFI.langevin` | Langevin simulators (`OverdampedProcess`, …) |
187
+ | `SFI.bases` | Ready-made basis builders (monomials, pairs, SPDE, …) |
188
+ | `SFI.diagnostics` | Residual tests, dynamics classifier, error checks |
189
+ | `SFI.integrate` | Time-averaging integration engine |
190
+ | `SFI.utils` | Math helpers, formatting, plotting |
191
+
192
+ ## Citation
193
+
194
+ If you use SFI, please cite the software (see [`CITATION.cff`](https://github.com/ronceray/StochasticForceInference/blob/main/CITATION.cff))
195
+ together with the method paper(s) relevant to the features you use.
196
+
197
+ The software is archived on Zenodo. Cite the concept DOI
198
+ [10.5281/zenodo.21532842](https://doi.org/10.5281/zenodo.21532842), which always
199
+ resolves to the latest release; each version also has its own DOI (v2.0.4:
200
+ [10.5281/zenodo.23498743](https://doi.org/10.5281/zenodo.23498743)).
201
+
202
+ See **[How to cite](https://stochasticforceinference.readthedocs.io/en/latest/#how-to-cite)** in the
203
+ documentation for the full, feature-specific list (overdamped, underdamped/ULI,
204
+ trapeze, and PASTIS references).
205
+
206
+ ## Funding
207
+
208
+ Funded by the European Union (ERC, SuperStoc, 101117322). Views and opinions
209
+ expressed are however those of the author(s) only and do not necessarily
210
+ reflect those of the European Union or the European Research Council Executive
211
+ Agency. Neither the European Union nor the granting authority can be held
212
+ responsible for them. P. R. also acknowledges funding from the French National
213
+ Research Agency (ANR-16-CONV-0001) and from the Excellence Initiative of
214
+ Aix-Marseille University A\*MIDEX.
215
+
216
+ ## License
217
+
218
+ MIT — see [LICENSE](https://github.com/ronceray/StochasticForceInference/blob/main/LICENSE) for details.