stochasticforceinference 2.0.4__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 (183) hide show
  1. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/AGENTS.md +63 -12
  2. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/MANIFEST.in +1 -0
  3. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/PKG-INFO +94 -43
  4. stochasticforceinference-2.1.0/README.md +218 -0
  5. stochasticforceinference-2.1.0/SFI/AGENT_GUIDE.md +231 -0
  6. {stochasticforceinference-2.0.4 → 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.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/__init__.py +4 -2
  10. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/assess.py +13 -3
  11. stochasticforceinference-2.1.0/SFI/diagnostics/diffusion_check.py +63 -0
  12. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/dynamics_order.py +4 -2
  13. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/finite_dt.py +17 -10
  14. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/report.py +42 -10
  15. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/residuals.py +21 -15
  16. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/__init__.py +3 -1
  17. stochasticforceinference-2.1.0/SFI/inference/_oli_diffusion.py +667 -0
  18. stochasticforceinference-2.1.0/SFI/inference/_oli_instrument.py +1049 -0
  19. stochasticforceinference-2.1.0/SFI/inference/_uli_constant_noise.py +931 -0
  20. stochasticforceinference-2.1.0/SFI/inference/_uli_diffusion.py +348 -0
  21. stochasticforceinference-2.1.0/SFI/inference/_uli_drift_check.py +103 -0
  22. stochasticforceinference-2.1.0/SFI/inference/_uli_model_free.py +729 -0
  23. stochasticforceinference-2.1.0/SFI/inference/_uli_path_resolution.py +143 -0
  24. stochasticforceinference-2.1.0/SFI/inference/_uli_stride.py +258 -0
  25. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/base.py +182 -44
  26. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/graph_diffusion.py +16 -2
  27. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/overdamped.py +530 -57
  28. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/runner.py +2 -3
  29. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/solve.py +62 -72
  30. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/__init__.py +20 -1
  31. stochasticforceinference-2.1.0/SFI/inference/sparse/exhaustive.py +107 -0
  32. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/hillclimb.py +9 -4
  33. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/result.py +187 -0
  34. stochasticforceinference-2.1.0/SFI/inference/sparse/units.py +514 -0
  35. stochasticforceinference-2.1.0/SFI/inference/underdamped.py +3445 -0
  36. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/integrate/api.py +178 -17
  37. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/integrate/integrand.py +128 -66
  38. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/underdamped.py +33 -19
  39. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/dataset.py +9 -8
  40. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/utils/maths.py +102 -7
  41. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/utils/plotting.py +12 -5
  42. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/PKG-INFO +94 -43
  43. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/SOURCES.txt +17 -1
  44. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/requires.txt +2 -2
  45. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/abp_align_demo.py +30 -33
  46. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/abp_nonreciprocal_demo.py +25 -24
  47. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/abp_to_spde_demo.py +6 -3
  48. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/advanced/flocking_3d_demo.py +45 -26
  49. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/advanced/multi_experiment_demo.py +2 -2
  50. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/advanced/nn_force_demo.py +3 -3
  51. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/anisotropic_diffusion_demo.py +8 -9
  52. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/custom_basis_demo.py +7 -9
  53. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/diagnostics_demo.py +2 -2
  54. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/entropy_production_demo.py +16 -17
  55. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/entropy_production_underdamped_demo.py +49 -35
  56. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/experimental_workflow_demo.py +13 -15
  57. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/gray_scott_demo.py +41 -45
  58. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/janus_colloids_demo.py +34 -34
  59. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/limitcycle_demo.py +16 -16
  60. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/lorenz_demo.py +5 -6
  61. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/lotka_volterra_demo.py +56 -58
  62. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/multiplicative_diffusion_demo.py +23 -14
  63. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/ou_demo.py +5 -7
  64. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/time_dependent_forcing_demo.py +6 -7
  65. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/time_fourier_demo.py +4 -4
  66. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/van_der_pol_demo.py +47 -27
  67. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/velocity_dependent_noise_demo.py +10 -11
  68. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/pyproject.toml +23 -7
  69. stochasticforceinference-2.1.0/tests/test_agent_guide.py +162 -0
  70. stochasticforceinference-2.1.0/tests/test_version.py +50 -0
  71. stochasticforceinference-2.0.4/README.md +0 -170
  72. stochasticforceinference-2.0.4/SFI/inference/underdamped.py +0 -2231
  73. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/CONTRIBUTING.md +0 -0
  74. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/GALLERY_STYLE_GUIDE.md +0 -0
  75. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/LICENSE +0 -0
  76. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/__init__.py +0 -0
  77. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/constants.py +0 -0
  78. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/linear.py +0 -0
  79. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/monomials.py +0 -0
  80. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/pairs.py +0 -0
  81. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/bases/spde.py +0 -0
  82. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/plotting.py +0 -0
  83. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/psd.py +0 -0
  84. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/diagnostics/residual_tests.py +0 -0
  85. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/optimizers.py +0 -0
  86. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/__init__.py +0 -0
  87. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/banded.py +0 -0
  88. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/covariance.py +0 -0
  89. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/driver.py +0 -0
  90. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow.py +0 -0
  91. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow_multi.py +0 -0
  92. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/flow_ud.py +0 -0
  93. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/frame_extras.py +0 -0
  94. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/gram.py +0 -0
  95. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/jacobians.py +0 -0
  96. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/parametric_core/precompute.py +0 -0
  97. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/result.py +0 -0
  98. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/serialization.py +0 -0
  99. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/base.py +0 -0
  100. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/beam.py +0 -0
  101. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/greedy.py +0 -0
  102. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/lasso.py +0 -0
  103. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/metrics.py +0 -0
  104. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/scorer.py +0 -0
  105. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparse/stlsq.py +0 -0
  106. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/inference/sparsity.py +0 -0
  107. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/integrate/__init__.py +0 -0
  108. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/integrate/rk4.py +0 -0
  109. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/integrate/timeops.py +0 -0
  110. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/__init__.py +0 -0
  111. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/base.py +0 -0
  112. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/chunked.py +0 -0
  113. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/graph_noise.py +0 -0
  114. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/noise.py +0 -0
  115. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/langevin/overdamped.py +0 -0
  116. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/__init__.py +0 -0
  117. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/basis.py +0 -0
  118. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/core/runtime.py +0 -0
  119. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/factory.py +0 -0
  120. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/interactor.py +0 -0
  121. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/__init__.py +0 -0
  122. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_base.py +0 -0
  123. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_eval_compiler.py +0 -0
  124. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_fd_atoms.py +0 -0
  125. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_grid.py +0 -0
  126. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/layout/_sectors.py +0 -0
  127. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/memhint.py +0 -0
  128. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/__init__.py +0 -0
  129. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/base.py +0 -0
  130. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/contract.py +0 -0
  131. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/__init__.py +0 -0
  132. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/dispatcher.py +0 -0
  133. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/prepare.py +0 -0
  134. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/specs.py +0 -0
  135. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/interactions/stencils.py +0 -0
  136. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/leaf.py +0 -0
  137. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/__init__.py +0 -0
  138. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/concat.py +0 -0
  139. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/derivative.py +0 -0
  140. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/einsum.py +0 -0
  141. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/linear.py +0 -0
  142. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/mapn.py +0 -0
  143. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/reshape_rank.py +0 -0
  144. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/nodes/ops/slice.py +0 -0
  145. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/params.py +0 -0
  146. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/psf.py +0 -0
  147. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/sf.py +0 -0
  148. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/stateexpr.py +0 -0
  149. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/statefunc/structexpr.py +0 -0
  150. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/__init__.py +0 -0
  151. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/collection.py +0 -0
  152. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/degrade.py +0 -0
  153. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/io.py +0 -0
  154. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/trajectory/reserved_extras.py +0 -0
  155. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/utils/__init__.py +0 -0
  156. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/utils/formatting.py +0 -0
  157. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/SFI/utils/neighbors.py +0 -0
  158. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/dependency_links.txt +0 -0
  159. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/StochasticForceInference.egg-info/top_level.txt +0 -0
  160. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/__init__.py +0 -0
  161. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/abp.py +0 -0
  162. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/bench_utils.py +0 -0
  163. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/coarse_grain.py +0 -0
  164. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/helpers.py +0 -0
  165. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/janus_colloids.py +0 -0
  166. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/_gallery_utils/scenario_picker.py +0 -0
  167. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/experimental_data/_analyze_results.py +0 -0
  168. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/experimental_data/_expanded_basis.py +0 -0
  169. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/experimental_data/generate_tweezer_csv.py +0 -0
  170. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/dynamics_order_demo.py +0 -0
  171. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/gallery/home_range_demo.py +0 -0
  172. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_align_demo.py +0 -0
  173. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_config.py +0 -0
  174. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_demo.py +0 -0
  175. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_infer.py +0 -0
  176. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_plot.py +0 -0
  177. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_largescale_simulate.py +0 -0
  178. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/examples/manual_examples/abp_pursuit_demo.py +0 -0
  179. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/setup.cfg +0 -0
  180. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/tests/test_dual_mask.py +0 -0
  181. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/tests/test_parametric_mask.py +0 -0
  182. {stochasticforceinference-2.0.4 → stochasticforceinference-2.1.0}/tests/test_parametric_mask_abp.py +0 -0
  183. {stochasticforceinference-2.0.4 → 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
 
@@ -46,6 +50,7 @@ SFI has mature, well-tested abstractions for every common operation.
46
50
  | Run force / diffusion inference | `SFI.OverdampedLangevinInference` / `UnderdampedLangevinInference` |
47
51
  | Select a sparse model | `inf.sparsify_force(criterion="PASTIS", p=0.1)` |
48
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`) |
49
54
  | Compare to ground truth | `inf.compare_to_exact(model_exact=...)` |
50
55
  | Plot in the SFI style | `SFI.utils.plotting.SFI_COLORS`, `dark_fig`, `phase2d` |
51
56
  | Save / load a fitted model | `SFI.inference.save_model` / `load_model` |
@@ -82,9 +87,30 @@ positions; see `SFI.diagnostics` and `examples/gallery/dynamics_order_demo.py`.
82
87
  `SFI.diagnostics.finite_dt_scale(inf)` reports the per-step drift-gradient
83
88
  scale Δt‖∇F̂‖ of a fitted force (the size of the linear estimators' O(Δt)
84
89
  biases) with a `fine` / `coarse` / `unreliable` verdict; `assess(inf)` includes
85
- it and flags the coarse regimes. Both linear engines also record the force
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
86
95
  Gram condition number (`metadata["force_gram_cond"]`) and warn when the
87
- dictionary is ill-conditioned on the data.
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.
88
114
  `SFI.diagnostics.psd_fraction(D_sf, coll)` reports the fraction of data
89
115
  points where a diffusion field is not positive semi-definite;
90
116
  `simulate_bootstrapped_trajectory` runs it on the fitted diffusion and warns
@@ -145,7 +171,7 @@ agreement is itself a diagnostic.
145
171
  | `inf.print_report()` / `inf.report_dict()` | Human / machine summary |
146
172
  | `inf.compare_to_exact(model_exact=...)` | Validate against a known model |
147
173
  | `inf.holdout_score(test)` | Held-out NMSE on `coll.split_time(...)` test data (data-abundant scenarios only) |
148
- | `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) |
149
175
  | `inf.time_reversal_split()` | Underdamped only: the fitted field's reversible/irreversible parts `(F_even, F_odd)` as callables |
150
176
 
151
177
  * **Parametric estimators (robust, flexible; compute-intensive).**
@@ -190,14 +216,14 @@ agreement is itself a diagnostic.
190
216
 
191
217
  ```python
192
218
  inf = OverdampedLangevinInference(collection)
193
- inf.compute_diffusion_constant(method="auto") # 1. constant D ("noisy"/"WeakNoise"/"MSD")
194
- inf.infer_force_linear(basis, preset="auto") # 2. force ("auto"/"robust"/"clean"/"KM"/legacy)
195
- inf.infer_diffusion_linear() # 3. optional: constant sym D (default basis)
196
- inf.compute_force_error() # 4. error analysis
197
- inf.sparsify_force(criterion="PASTIS", p=0.1) # 5. optional: sparsity
198
- inf.compute_entropy_production() # 6. optional: dissipation (OD & UD)
199
- inf.print_report() # 7. summary
200
- 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
201
227
  ```
202
228
 
203
229
  **Parametric-estimator sequence:**
@@ -211,10 +237,19 @@ inf.compute_force_error()
211
237
 
212
238
  **Sparsity.** PASTIS is the canonical criterion in SFI. Alternative
213
239
  criteria (`AIC`, `BIC`, `SIC`) and strategies (greedy stepwise,
214
- STLSQ, LASSO) are available — see
240
+ STLSQ, LASSO, `method="exhaustive"` for the exact front of small
241
+ candidate sets) are available — see
215
242
  [`_project_index/api_map.md`](_project_index/api_map.md#sfiinferencesparse)
216
243
  for the full inventory. Precision/recall and held-out NMSE helpers
217
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.
218
253
 
219
254
  ### 4.4 `SFI.trajectory` — data containers
220
255
 
@@ -365,6 +400,21 @@ Deprecated / soon-to-be-removed symbols (do not use in new code):
365
400
  deprecated tuning knobs, accepted but **inert** (a
366
401
  `DeprecationWarning` fires when set). The banded likelihood has no
367
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).
368
418
 
369
419
  ## 6. Testing, building, environment
370
420
 
@@ -374,6 +424,7 @@ Full details: [`docs/source/dev_notes.rst`](docs/source/dev_notes.rst).
374
424
  source .venv/bin/activate
375
425
  pytest tests/ -v # full suite (CPU-only via conftest)
376
426
  pytest tests/ -x --ff # quick smoke
427
+ pytest tests/inference -m sparsity # when changing sparse selection (deselected by default)
377
428
  cd docs && make clean && make html # fast docs build
378
429
  cd docs && SFI_DOCS_RUN_GALLERY=1 make html # full build (slow)
379
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.4
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
@@ -60,13 +63,36 @@ Dynamic: license-file
60
63
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/ronceray/StochasticForceInference/blob/main/LICENSE)
61
64
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21532842.svg)](https://doi.org/10.5281/zenodo.21532842)
62
65
 
63
- **Infer force and diffusion fields from stochastic trajectory data.**
64
-
65
- SFI is a JAX-based Python package for learning the drift (force) and diffusion
66
- of Langevin stochastic differential equations from time-series observations.
67
- It handles both overdamped and underdamped dynamics, supports interacting
68
- particles and spatially-extended (SPDE) systems, and provides built-in
69
- diagnostics, sparse model selection, and bootstrapped validation.
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).
70
96
 
71
97
  > **Designed for experimental data.** SFI is built for real experimental
72
98
  > trajectories (tracked particles, cells, organisms, …) where *no dynamical
@@ -80,10 +106,11 @@ diagnostics, sparse model selection, and bootstrapped validation.
80
106
  ## Key features
81
107
 
82
108
  - **Two estimator families** — closed-form linear estimators
83
- (`infer_force_linear`, seconds even on large datasets) and parametric
84
- estimators (`infer_force` / `infer_diffusion`: noise-aware likelihood
85
- fit, robust to localization error and coarse sampling, accepts
86
- 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).
87
114
  - **Overdamped & underdamped inference** — works with position-only data;
88
115
  velocities are reconstructed automatically for underdamped systems.
89
116
  - **Composable state functions** — build force/diffusion models from
@@ -91,18 +118,21 @@ diagnostics, sparse model selection, and bootstrapped validation.
91
118
  parametric families, all with automatic differentiation via JAX.
92
119
  - **Sparse model selection** — Pareto-front beam search with AIC / BIC /
93
120
  PASTIS information criteria.
94
- - **Simulation** — simulate Langevin SDEs (Euler–Maruyama) from the same
95
- 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.
96
125
  - **Trajectory toolkit** — mask-aware increments, synthetic degradation
97
126
  (noise, downsampling, data loss, motion blur), streaming for large
98
- datasets, I/O (CSV / Parquet / HDF5).
99
- - **Diagnostics** — compare inferred fields to exact models, compute
100
- 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.
101
131
 
102
132
  ## Installation
103
133
 
104
134
  ```bash
105
- pip install StochasticForceInference
135
+ pip install StochasticForceInference # import name: SFI
106
136
  ```
107
137
 
108
138
  For development (editable install with test/doc dependencies):
@@ -131,12 +161,13 @@ coll = TrajectoryCollection.from_arrays(X=positions, dt=0.01)
131
161
  # Infer using a polynomial basis — no model needed
132
162
  B = monomials_up_to(order=3, dim=2, rank="vector")
133
163
  inf = OverdampedLangevinInference(coll)
134
- inf.compute_diffusion_constant()
135
- inf.infer_force_linear(B)
164
+ inf.infer_force_linear(B) # also estimates D and the measurement noise
136
165
  inf.sparsify_force(criterion="PASTIS") # optional: find the minimal model
137
- 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
138
169
 
139
- # Noisy or coarsely-sampled recordings? Use the parametric estimator
170
+ # Coarsely sampled or very noisy recordings? Use the parametric estimator
140
171
  # instead: inf.infer_force(B) — it models the measurement noise natively.
141
172
  ```
142
173
 
@@ -159,7 +190,6 @@ coll = proc.simulate(dt=0.01, Nsteps=10_000, key=random.PRNGKey(0))
159
190
  # 2. Infer from the trajectory using a generic polynomial basis
160
191
  B = monomials_up_to(order=2, dim=2, rank="vector")
161
192
  inf = OverdampedLangevinInference(coll)
162
- inf.compute_diffusion_constant()
163
193
  inf.infer_force_linear(B)
164
194
  inf.compute_force_error()
165
195
 
@@ -168,11 +198,35 @@ inf.print_report()
168
198
  inf.compare_to_exact(model_exact=proc)
169
199
  ```
170
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
+
171
224
  ## Documentation
172
225
 
173
226
  Full documentation is available at
174
227
  [stochasticforceinference.readthedocs.io](https://stochasticforceinference.readthedocs.io), including:
175
228
 
229
+ - **[Start here](https://stochasticforceinference.readthedocs.io/en/latest/start_here.html)** — is SFI right for my data, and which route to take
176
230
  - **[Tutorial](https://stochasticforceinference.readthedocs.io/en/latest/gallery/ou_demo.html)** — end-to-end walkthrough
177
231
  - **[Examples gallery](https://stochasticforceinference.readthedocs.io/en/latest/gallery/index.html)** — worked examples covering sparsity, multi-particle, and SPDE inference
178
232
  - **[Model building](https://stochasticforceinference.readthedocs.io/en/latest/statefunc/user_guide.html)** — composable state functions
@@ -182,29 +236,26 @@ Full documentation is available at
182
236
 
183
237
  ## Package structure
184
238
 
185
- | Subpackage | Purpose |
186
- | ---------------- | ---------------------------------------------------- |
187
- | `SFI.statefunc` | Composable state functions: `Basis`, `PSF`, `SF` |
188
- | `SFI.inference` | Overdamped & underdamped inference engines |
189
- | `SFI.trajectory` | `TrajectoryCollection` / `TrajectoryDataset` |
190
- | `SFI.langevin` | Langevin simulators (`OverdampedProcess`, …) |
191
- | `SFI.bases` | Ready-made basis builders (monomials, constants, …) |
192
- | `SFI.integrate` | Time-averaging integration engine |
193
- | `SFI.utils` | Math helpers, formatting, plotting |
194
-
195
- For contributors and AI coding agents: see [`AGENTS.md`](https://github.com/ronceray/StochasticForceInference/blob/main/AGENTS.md) for
196
- the canonical imports table, task playbooks, and "do not re-implement"
197
- 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 |
198
249
 
199
250
  ## Citation
200
251
 
201
- If you use SFI, please cite the software (see [`CITATION.cff`](CITATION.cff))
252
+ If you use SFI, please cite the software (see [`CITATION.cff`](https://github.com/ronceray/StochasticForceInference/blob/main/CITATION.cff))
202
253
  together with the method paper(s) relevant to the features you use.
203
254
 
204
255
  The software is archived on Zenodo. Cite the concept DOI
205
256
  [10.5281/zenodo.21532842](https://doi.org/10.5281/zenodo.21532842), which always
206
- resolves to the latest release; each version also has its own DOI (v2.0.3:
207
- [10.5281/zenodo.21532843](https://doi.org/10.5281/zenodo.21532843)).
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)).
208
259
 
209
260
  See **[How to cite](https://stochasticforceinference.readthedocs.io/en/latest/#how-to-cite)** in the
210
261
  documentation for the full, feature-specific list (overdamped, underdamped/ULI,
@@ -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.