StochasticForceInference 2.0.0__py3-none-any.whl

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 (104) hide show
  1. SFI/__init__.py +64 -0
  2. SFI/bases/__init__.py +85 -0
  3. SFI/bases/constants.py +492 -0
  4. SFI/bases/linear.py +325 -0
  5. SFI/bases/monomials.py +218 -0
  6. SFI/bases/pairs.py +998 -0
  7. SFI/bases/spde.py +1537 -0
  8. SFI/diagnostics/__init__.py +60 -0
  9. SFI/diagnostics/assess.py +87 -0
  10. SFI/diagnostics/dynamics_order.py +621 -0
  11. SFI/diagnostics/plotting.py +226 -0
  12. SFI/diagnostics/report.py +238 -0
  13. SFI/diagnostics/residual_tests.py +395 -0
  14. SFI/diagnostics/residuals.py +688 -0
  15. SFI/inference/__init__.py +58 -0
  16. SFI/inference/base.py +1460 -0
  17. SFI/inference/optimizers.py +200 -0
  18. SFI/inference/overdamped.py +1214 -0
  19. SFI/inference/parametric_core/__init__.py +34 -0
  20. SFI/inference/parametric_core/covariance.py +232 -0
  21. SFI/inference/parametric_core/driver.py +272 -0
  22. SFI/inference/parametric_core/flow.py +149 -0
  23. SFI/inference/parametric_core/flow_multi.py +362 -0
  24. SFI/inference/parametric_core/flow_ud.py +168 -0
  25. SFI/inference/parametric_core/jacobians.py +540 -0
  26. SFI/inference/parametric_core/objective.py +286 -0
  27. SFI/inference/parametric_core/objective_ud.py +253 -0
  28. SFI/inference/parametric_core/precision.py +229 -0
  29. SFI/inference/parametric_core/solve.py +763 -0
  30. SFI/inference/result.py +362 -0
  31. SFI/inference/serialization.py +245 -0
  32. SFI/inference/sparse/__init__.py +67 -0
  33. SFI/inference/sparse/base.py +43 -0
  34. SFI/inference/sparse/beam.py +303 -0
  35. SFI/inference/sparse/greedy.py +151 -0
  36. SFI/inference/sparse/hillclimb.py +307 -0
  37. SFI/inference/sparse/lasso.py +178 -0
  38. SFI/inference/sparse/metrics.py +78 -0
  39. SFI/inference/sparse/result.py +278 -0
  40. SFI/inference/sparse/scorer.py +323 -0
  41. SFI/inference/sparse/stlsq.py +165 -0
  42. SFI/inference/sparsity.py +40 -0
  43. SFI/inference/underdamped.py +1355 -0
  44. SFI/integrate/__init__.py +38 -0
  45. SFI/integrate/api.py +920 -0
  46. SFI/integrate/integrand.py +402 -0
  47. SFI/integrate/rk4.py +156 -0
  48. SFI/integrate/timeops.py +174 -0
  49. SFI/langevin/__init__.py +29 -0
  50. SFI/langevin/base.py +863 -0
  51. SFI/langevin/chunked.py +225 -0
  52. SFI/langevin/noise.py +446 -0
  53. SFI/langevin/overdamped.py +560 -0
  54. SFI/langevin/underdamped.py +448 -0
  55. SFI/statefunc/__init__.py +49 -0
  56. SFI/statefunc/basis.py +87 -0
  57. SFI/statefunc/core/runtime.py +47 -0
  58. SFI/statefunc/factory.py +346 -0
  59. SFI/statefunc/interactor.py +90 -0
  60. SFI/statefunc/layout/__init__.py +29 -0
  61. SFI/statefunc/layout/_base.py +186 -0
  62. SFI/statefunc/layout/_eval_compiler.py +453 -0
  63. SFI/statefunc/layout/_fd_atoms.py +196 -0
  64. SFI/statefunc/layout/_grid.py +878 -0
  65. SFI/statefunc/layout/_sectors.py +166 -0
  66. SFI/statefunc/memhint.py +222 -0
  67. SFI/statefunc/nodes/__init__.py +56 -0
  68. SFI/statefunc/nodes/base.py +318 -0
  69. SFI/statefunc/nodes/contract.py +422 -0
  70. SFI/statefunc/nodes/interactions/__init__.py +23 -0
  71. SFI/statefunc/nodes/interactions/dispatcher.py +1365 -0
  72. SFI/statefunc/nodes/interactions/prepare.py +161 -0
  73. SFI/statefunc/nodes/interactions/specs.py +362 -0
  74. SFI/statefunc/nodes/interactions/stencils.py +718 -0
  75. SFI/statefunc/nodes/leaf.py +530 -0
  76. SFI/statefunc/nodes/ops/__init__.py +27 -0
  77. SFI/statefunc/nodes/ops/concat.py +28 -0
  78. SFI/statefunc/nodes/ops/derivative.py +447 -0
  79. SFI/statefunc/nodes/ops/einsum.py +120 -0
  80. SFI/statefunc/nodes/ops/linear.py +153 -0
  81. SFI/statefunc/nodes/ops/mapn.py +138 -0
  82. SFI/statefunc/nodes/ops/reshape_rank.py +158 -0
  83. SFI/statefunc/nodes/ops/slice.py +83 -0
  84. SFI/statefunc/params.py +309 -0
  85. SFI/statefunc/psf.py +112 -0
  86. SFI/statefunc/sf.py +104 -0
  87. SFI/statefunc/stateexpr.py +1243 -0
  88. SFI/statefunc/structexpr.py +1003 -0
  89. SFI/trajectory/__init__.py +31 -0
  90. SFI/trajectory/collection.py +1122 -0
  91. SFI/trajectory/dataset.py +1164 -0
  92. SFI/trajectory/degrade.py +1108 -0
  93. SFI/trajectory/io.py +1027 -0
  94. SFI/trajectory/reserved_extras.py +129 -0
  95. SFI/utils/__init__.py +17 -0
  96. SFI/utils/formatting.py +308 -0
  97. SFI/utils/maths.py +185 -0
  98. SFI/utils/neighbors.py +162 -0
  99. SFI/utils/plotting.py +1936 -0
  100. stochasticforceinference-2.0.0.dist-info/METADATA +203 -0
  101. stochasticforceinference-2.0.0.dist-info/RECORD +104 -0
  102. stochasticforceinference-2.0.0.dist-info/WHEEL +5 -0
  103. stochasticforceinference-2.0.0.dist-info/licenses/LICENSE +21 -0
  104. stochasticforceinference-2.0.0.dist-info/top_level.txt +1 -0
SFI/utils/neighbors.py ADDED
@@ -0,0 +1,162 @@
1
+ """Cell-list neighbor builder for truncated-range pair interactions.
2
+
3
+ Provides :func:`build_neighbor_csr` which constructs a sparse CSR
4
+ neighbor list from particle positions and a cutoff radius, using
5
+ ``scipy.spatial.cKDTree``. The returned ``(indptr, indices)`` arrays
6
+ plug directly into ``dispatch_pairs_from_extras``.
7
+
8
+ All routines run on the host (pure NumPy) and are meant to be called
9
+ *between* JIT-compiled simulation chunks, not inside ``jax.lax.scan``.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Optional, Tuple
15
+
16
+ import jax.numpy as jnp
17
+ import numpy as np
18
+ from scipy.spatial import cKDTree
19
+
20
+
21
+ def build_neighbor_csr(
22
+ positions: np.ndarray,
23
+ cutoff: float,
24
+ box: Optional[np.ndarray] = None,
25
+ *,
26
+ exclude_self: bool = True,
27
+ ) -> Tuple[np.ndarray, np.ndarray]:
28
+ """Build a CSR neighbor list using ``scipy.spatial.cKDTree``.
29
+
30
+ Parameters
31
+ ----------
32
+ positions : ndarray, shape ``(N, d)``
33
+ Particle positions (spatial coordinates only).
34
+ cutoff : float
35
+ Cutoff radius. Pairs with ``r_ij > cutoff`` are excluded.
36
+ box : ndarray, shape ``(d,)``, optional
37
+ Periodic box lengths. If *None*, open (non-periodic) boundaries.
38
+ exclude_self : bool
39
+ If *True* (default), self-pairs ``(i, i)`` are never included.
40
+
41
+ Returns
42
+ -------
43
+ indptr : ndarray, shape ``(N + 1,)``, dtype int32
44
+ CSR row pointers.
45
+ indices : ndarray, shape ``(nnz,)``, dtype int32
46
+ CSR column indices (neighbour particle indices).
47
+ """
48
+ positions = np.asarray(positions, dtype=np.float64)
49
+ N, d = positions.shape
50
+
51
+ if N == 0:
52
+ return (
53
+ np.zeros(1, dtype=np.int32),
54
+ np.empty(0, dtype=np.int32),
55
+ )
56
+
57
+ # --- wrap positions into the primary box ---
58
+ if box is not None:
59
+ box = np.asarray(box, dtype=np.float64)
60
+ positions = positions % box
61
+
62
+ # --- build KD-tree and query pairs ---
63
+ boxsize = box if box is not None else None
64
+ tree = cKDTree(positions, boxsize=boxsize)
65
+ csr = tree.sparse_distance_matrix(tree, cutoff, output_type="coo_matrix")
66
+ csr = csr.tocsr()
67
+
68
+ if exclude_self:
69
+ csr.setdiag(0)
70
+ csr.eliminate_zeros()
71
+
72
+ indptr = csr.indptr.astype(np.int32)
73
+ indices = csr.indices.astype(np.int32)
74
+
75
+ return indptr, indices
76
+
77
+
78
+ def make_neighbor_extras(
79
+ positions: np.ndarray,
80
+ cutoff: float,
81
+ box: Optional[np.ndarray] = None,
82
+ *,
83
+ indptr_key: str = "indptr",
84
+ indices_key: str = "indices",
85
+ exclude_self: bool = True,
86
+ ) -> dict:
87
+ """Build a CSR neighbor list and return it as an extras dict.
88
+
89
+ Convenience wrapper around :func:`build_neighbor_csr`. The returned
90
+ dict is ready to be merged into ``extras_global`` for a process that
91
+ uses ``dispatch_pairs_from_extras(indptr_key, indices_key)``.
92
+
93
+ Parameters
94
+ ----------
95
+ positions, cutoff, box, exclude_self
96
+ Forwarded to :func:`build_neighbor_csr`.
97
+ indptr_key, indices_key
98
+ Keys under which CSR arrays are stored.
99
+
100
+ Returns
101
+ -------
102
+ dict
103
+ ``{indptr_key: indptr, indices_key: indices}``
104
+ """
105
+ indptr, indices = build_neighbor_csr(
106
+ positions,
107
+ cutoff,
108
+ box,
109
+ exclude_self=exclude_self,
110
+ )
111
+ return {
112
+ indptr_key: jnp.array(indptr),
113
+ indices_key: jnp.array(indices),
114
+ }
115
+
116
+
117
+ def pad_neighbor_csr(
118
+ indptr: np.ndarray,
119
+ indices: np.ndarray,
120
+ max_nnz: int,
121
+ *,
122
+ fill_index: int = 0,
123
+ ) -> Tuple[np.ndarray, np.ndarray]:
124
+ """Pad a CSR neighbor list to a fixed ``max_nnz``.
125
+
126
+ JAX JIT recompiles when array shapes change. Padding the indices
127
+ array to a fixed length avoids recompilation across simulation
128
+ chunks with fluctuating neighbor counts.
129
+
130
+ Excess entries are filled with ``fill_index`` (default 0). Because
131
+ ``indptr`` keeps the true lengths, the dispatcher will only iterate
132
+ over the real neighbours — the padded entries are never evaluated.
133
+
134
+ .. note::
135
+ This only pads ``indices``. ``indptr`` is left unchanged (always
136
+ ``N + 1`` long). If the actual nnz exceeds ``max_nnz``, a
137
+ ``ValueError`` is raised.
138
+
139
+ Parameters
140
+ ----------
141
+ indptr, indices
142
+ As returned by :func:`build_neighbor_csr`.
143
+ max_nnz : int
144
+ Target length for ``indices``.
145
+ fill_index : int
146
+ Index used to fill padded entries.
147
+
148
+ Returns
149
+ -------
150
+ indptr, indices_padded
151
+ Same ``indptr``, padded ``indices`` of length ``max_nnz``.
152
+ """
153
+ nnz = len(indices)
154
+ if nnz > max_nnz:
155
+ raise ValueError(
156
+ f"Actual nnz ({nnz}) exceeds max_nnz ({max_nnz}). Increase max_nnz or enlarge the cutoff safety margin."
157
+ )
158
+ if nnz == max_nnz:
159
+ return indptr, indices
160
+ padded = np.full(max_nnz, fill_index, dtype=indices.dtype)
161
+ padded[:nnz] = indices
162
+ return indptr, padded