jflows 0.5.3__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.
jflows-0.5.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xuda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
jflows-0.5.3/PKG-INFO ADDED
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: jflows
3
+ Version: 0.5.3
4
+ Summary: JAX normalizing flows for unconditional energy-based sampling and Boltzmann generators.
5
+ Author-email: Xuda <abneryepku@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/xuda-ye-math/jflows
8
+ Keywords: normalizing-flows,boltzmann-generator,jax,equinox,sampling,smc,neural-spline-flows,ot-flow
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: jax>=0.6.0
25
+ Requires-Dist: equinox>=0.13.0
26
+ Requires-Dist: numpy>=2.0.0
27
+ Provides-Extra: examples
28
+ Requires-Dist: matplotlib>=3.8; extra == "examples"
29
+ Dynamic: license-file
30
+
31
+ <p align="center"><img src="jflows.png" alt="jflows banner" width="800px"></p>
32
+ <p align="center"><sub><em>Banner designed by ChatGPT: the character Jax from "The Amazing Digital Circus", a nod to jflows being built on Google JAX.</em></sub></p>
33
+
34
+ # jflows
35
+
36
+ `jflows` is a JAX/Equinox package for unconditional normalizing flows,
37
+ energy-based sampling, and staged Boltzmann generators. It provides a small
38
+ public API for building flows, defining unnormalized target energies, training
39
+ one transport stage, and connecting accepted stages into a complete source-to-
40
+ target sampler.
41
+
42
+ > **Status: experimental.** The package is developed and tested on Linux with
43
+ > NVIDIA CUDA JAX. JAX GPU is not supported on Windows, including WSL.
44
+ >
45
+ > This project was developed with Codex.
46
+
47
+ ## Core features
48
+
49
+ - **First-class spline flows.** `NSF` models bounded Euclidean boxes and
50
+ `NCSF` models periodic boxes or tori. `CNF`, `OTFlow`, and `RealNVP` provide
51
+ complementary continuous and affine-coupling architectures.
52
+ - **One immutable flow interface.** Every flow provides `flow(x)`,
53
+ `flow.call_and_ladj(x)`, `flow.inv(y)`, and `flow.inv_and_ladj(y)` and works
54
+ as an Equinox pytree under JIT, vectorization, and differentiation.
55
+ - **Unified energy interface.** A `Potential` maps `[N,d]` samples to `[N]`
56
+ energies for densities proportional to `exp(-U)`. Built-in uniform, Gaussian,
57
+ and Gaussian-mixture potentials support explicit-key sampling, while
58
+ `potential_from` wraps a plain batched energy function.
59
+ - **Potential algebra.** Addition, subtraction, scaling, and
60
+ `linear_combination` construct bridge energies without introducing a second
61
+ target abstraction.
62
+ - **Explicit randomness.** Every random constructor and sampler takes a JAX
63
+ PRNG key. There is no package-global random state.
64
+ - **Sampling and diagnostics.** Importance weights, normalized ESS, coverage,
65
+ resampling, Langevin/MALA, stochastic Heun, HMC, SMC, flow-proposal AIS,
66
+ L-BFGS, AdamW, and quench-and-temper are available from `jflows.utils`.
67
+ - **Runtime backend report.** `jflows.backend()` lists CPU and installed JAX
68
+ accelerator plugins backed by visible hardware, identifies the configured
69
+ runtime, and reports JAX/Equinox versions and accelerator models without
70
+ creating a JAX device client or performing device computation.
71
+ - **Progressive training objectives.** Reverse KL, forward KL, KLX, and KLXX
72
+ share one validation convention while adding progressively richer
73
+ target-batch and density-ratio information.
74
+ - **Complete-stage persistence.** Boltzmann computation is separate from
75
+ optional stage writers/loaders, so an interrupted stage can be recomputed
76
+ from the last published population.
77
+
78
+ Flows are immutable. Identity initialization returns a new object:
79
+
80
+ ```python
81
+ flow = flow.zeros()
82
+ ```
83
+
84
+ `OTFlow` is the training exception: use `flow.near_identity()` so its
85
+ quadratic factor retains a nonzero gradient. Keep `OTFlow.zeros()` for an exact
86
+ identity map.
87
+
88
+ ## Three-level interface
89
+
90
+ The public API is deliberately arranged from basic numerical components to a
91
+ complete staged generator.
92
+
93
+ ### LOW — building blocks
94
+
95
+ The low level contains flows, potentials, per-sample losses, metrics, MCMC,
96
+ SMC/AIS, optimization, and quench-and-temper:
97
+
98
+ ```python
99
+ from jflows.flow import NSF, NCSF, CNF, OTFlow, RealNVP
100
+ from jflows.potential import Potential, Nlog_Gaussian, potential_from
101
+ from jflows.loss import reverse_KL_F, forward_KL_G, forward_KLX_G, forward_X_G
102
+ from jflows import backend
103
+ from jflows.utils import compute_ESS_log, importance_weights_log, langevin, smc
104
+ ```
105
+
106
+ `F` denotes the source-to-target map and `G = F^{-1}` the target-to-source
107
+ map. An `_F` or `_G` suffix fixes the native training direction.
108
+
109
+ ### MEDIUM — one-stage training
110
+
111
+ The medium level trains one map between a source and target potential:
112
+
113
+ ```python
114
+ from jflows.train import (
115
+ Monitor,
116
+ train_reverse_KL_F,
117
+ train_forward_KL_G,
118
+ train_forward_KLX_G,
119
+ train_forward_KLXX_G,
120
+ )
121
+ ```
122
+
123
+ Every trainer returns a new flow and its optimizer-batch ESS history. Simple
124
+ flow, sample, and history serialization lives in `jflows.artifacts`.
125
+
126
+ ### HIGH — staged Boltzmann generation
127
+
128
+ The high level connects accepted bridge stages and compares every trained map
129
+ with an exact identity fallback using full-validation incremental ESS:
130
+
131
+ ```python
132
+ from jflows.boltzmann import (
133
+ boltzmann_identity,
134
+ boltzmann_reverse_KL_F,
135
+ boltzmann_forward_KL_G,
136
+ boltzmann_forward_KLX_G,
137
+ boltzmann_forward_KLXX_G,
138
+ )
139
+ ```
140
+
141
+ - identity runs the adaptive-staging controller for stage selection, ESS
142
+ gating, resampling, and rejuvenation with no flow or optimizer;
143
+ - reverse KL is the simplest source-sampled F baseline;
144
+ - forward KL manufactures target-side batches and trains G;
145
+ - KLX adds target-measure log-weight variation control; and
146
+ - KLXX adds a quench-and-temper/proposal mixture for wider mode and leakage
147
+ regularization.
148
+
149
+ The four trained generators compare their candidate with identity. The
150
+ standalone `boltzmann_identity` function instead advances every accepted
151
+ stage by exact identity reweighting, so it requires no flow, batch size,
152
+ training steps, or learning rate. Complete-stage persistence is exposed
153
+ separately through `jflows.boltzmann.write` and `jflows.boltzmann.load`.
154
+
155
+ ## Minimal setup
156
+
157
+ ```bash
158
+ pip install "jax[cuda13]" equinox
159
+ pip install -e .
160
+ ```
161
+
162
+ ```python
163
+ import jflows
164
+
165
+ jflows.backend()
166
+ ```
167
+
168
+ A minimal training setup is:
169
+
170
+ ```python
171
+ import jax
172
+
173
+ from jflows.flow import NSF
174
+ from jflows.potential import Nlog_Gaussian, potential_from
175
+ from jflows.train import train_forward_KLX_G
176
+ from jflows.utils import compute_ESS_log, importance_weights_log
177
+
178
+ source = Nlog_Gaussian([0.0, 0.0], [1.0, 1.0])
179
+ target = potential_from(
180
+ lambda x: 10.0 * (jax.numpy.linalg.norm(x, axis=-1) - 2.0) ** 2
181
+ )
182
+
183
+ flow = NSF(
184
+ jax.random.key(0),
185
+ [-4.0, -4.0],
186
+ [4.0, 4.0],
187
+ bins=16,
188
+ transforms=4,
189
+ ).zeros()
190
+ x_valid = source.samples(jax.random.key(1), 20000)
191
+
192
+ flow, batch_ess = train_forward_KLX_G(
193
+ x_valid,
194
+ source,
195
+ target,
196
+ flow,
197
+ batch_size=500,
198
+ train_steps=200,
199
+ lr=1e-3,
200
+ ladder=1,
201
+ mc_dt=1e-3,
202
+ mc_steps=50,
203
+ coeff_lambda=1.0,
204
+ )
205
+
206
+ log_weights = importance_weights_log(
207
+ x_valid, source, target, flow, type="G"
208
+ )
209
+ validation_ess = compute_ESS_log(log_weights)
210
+ y_valid = flow.inv(x_valid)
211
+ ```
212
+
213
+ ## Repository map
214
+
215
+ ```text
216
+ jflows/
217
+ ├── doc/
218
+ │ ├── README.md # detailed documentation map
219
+ │ ├── 01-low-level.md
220
+ │ ├── 02-medium-level.md
221
+ │ ├── 03-high-level.md
222
+ │ ├── 04-smoke-tests.md
223
+ │ └── 05-examples.md
224
+ ├── jflows/
225
+ │ ├── flow.py # LOW
226
+ │ ├── potential.py # LOW
227
+ │ ├── loss.py # LOW
228
+ │ ├── utils/ # LOW
229
+ │ ├── train.py # MEDIUM
230
+ │ ├── artifacts.py # MEDIUM
231
+ │ ├── boltzmann/ # HIGH
232
+ │ └── core/ # private implementation
233
+ ├── smoke/ # narrow executable contracts
234
+ ├── example/ # complete workflows and results
235
+ └── README.md # this concise project introduction
236
+ ```
237
+
238
+ ## Read next
239
+
240
+ - **Detailed interface documentation:** [`doc/`](doc/README.md)
241
+ - **Executable API contracts:** [`smoke/`](smoke/)
242
+ - **Complete scripts, figures, and numerical results:**
243
+ [`example/`](example/) and [`example/results.md`](example/results.md)
244
+
245
+ The detailed documentation gives exact signatures, direction conventions,
246
+ return values, memory controls, stage records, and persistence behavior. Smoke
247
+ tests establish narrow software contracts; examples demonstrate end-to-end
248
+ scientific workflows.
249
+
250
+ ## Acknowledgements
251
+
252
+ `jflows` is strongly inspired by [zuko](https://github.com/probabilists/zuko).
253
+ The private flow, transform, and masked-MLP machinery in `jflows.core` is a
254
+ stripped-down port of zuko's clean and composable transform design.
jflows-0.5.3/README.md ADDED
@@ -0,0 +1,224 @@
1
+ <p align="center"><img src="jflows.png" alt="jflows banner" width="800px"></p>
2
+ <p align="center"><sub><em>Banner designed by ChatGPT: the character Jax from "The Amazing Digital Circus", a nod to jflows being built on Google JAX.</em></sub></p>
3
+
4
+ # jflows
5
+
6
+ `jflows` is a JAX/Equinox package for unconditional normalizing flows,
7
+ energy-based sampling, and staged Boltzmann generators. It provides a small
8
+ public API for building flows, defining unnormalized target energies, training
9
+ one transport stage, and connecting accepted stages into a complete source-to-
10
+ target sampler.
11
+
12
+ > **Status: experimental.** The package is developed and tested on Linux with
13
+ > NVIDIA CUDA JAX. JAX GPU is not supported on Windows, including WSL.
14
+ >
15
+ > This project was developed with Codex.
16
+
17
+ ## Core features
18
+
19
+ - **First-class spline flows.** `NSF` models bounded Euclidean boxes and
20
+ `NCSF` models periodic boxes or tori. `CNF`, `OTFlow`, and `RealNVP` provide
21
+ complementary continuous and affine-coupling architectures.
22
+ - **One immutable flow interface.** Every flow provides `flow(x)`,
23
+ `flow.call_and_ladj(x)`, `flow.inv(y)`, and `flow.inv_and_ladj(y)` and works
24
+ as an Equinox pytree under JIT, vectorization, and differentiation.
25
+ - **Unified energy interface.** A `Potential` maps `[N,d]` samples to `[N]`
26
+ energies for densities proportional to `exp(-U)`. Built-in uniform, Gaussian,
27
+ and Gaussian-mixture potentials support explicit-key sampling, while
28
+ `potential_from` wraps a plain batched energy function.
29
+ - **Potential algebra.** Addition, subtraction, scaling, and
30
+ `linear_combination` construct bridge energies without introducing a second
31
+ target abstraction.
32
+ - **Explicit randomness.** Every random constructor and sampler takes a JAX
33
+ PRNG key. There is no package-global random state.
34
+ - **Sampling and diagnostics.** Importance weights, normalized ESS, coverage,
35
+ resampling, Langevin/MALA, stochastic Heun, HMC, SMC, flow-proposal AIS,
36
+ L-BFGS, AdamW, and quench-and-temper are available from `jflows.utils`.
37
+ - **Runtime backend report.** `jflows.backend()` lists CPU and installed JAX
38
+ accelerator plugins backed by visible hardware, identifies the configured
39
+ runtime, and reports JAX/Equinox versions and accelerator models without
40
+ creating a JAX device client or performing device computation.
41
+ - **Progressive training objectives.** Reverse KL, forward KL, KLX, and KLXX
42
+ share one validation convention while adding progressively richer
43
+ target-batch and density-ratio information.
44
+ - **Complete-stage persistence.** Boltzmann computation is separate from
45
+ optional stage writers/loaders, so an interrupted stage can be recomputed
46
+ from the last published population.
47
+
48
+ Flows are immutable. Identity initialization returns a new object:
49
+
50
+ ```python
51
+ flow = flow.zeros()
52
+ ```
53
+
54
+ `OTFlow` is the training exception: use `flow.near_identity()` so its
55
+ quadratic factor retains a nonzero gradient. Keep `OTFlow.zeros()` for an exact
56
+ identity map.
57
+
58
+ ## Three-level interface
59
+
60
+ The public API is deliberately arranged from basic numerical components to a
61
+ complete staged generator.
62
+
63
+ ### LOW — building blocks
64
+
65
+ The low level contains flows, potentials, per-sample losses, metrics, MCMC,
66
+ SMC/AIS, optimization, and quench-and-temper:
67
+
68
+ ```python
69
+ from jflows.flow import NSF, NCSF, CNF, OTFlow, RealNVP
70
+ from jflows.potential import Potential, Nlog_Gaussian, potential_from
71
+ from jflows.loss import reverse_KL_F, forward_KL_G, forward_KLX_G, forward_X_G
72
+ from jflows import backend
73
+ from jflows.utils import compute_ESS_log, importance_weights_log, langevin, smc
74
+ ```
75
+
76
+ `F` denotes the source-to-target map and `G = F^{-1}` the target-to-source
77
+ map. An `_F` or `_G` suffix fixes the native training direction.
78
+
79
+ ### MEDIUM — one-stage training
80
+
81
+ The medium level trains one map between a source and target potential:
82
+
83
+ ```python
84
+ from jflows.train import (
85
+ Monitor,
86
+ train_reverse_KL_F,
87
+ train_forward_KL_G,
88
+ train_forward_KLX_G,
89
+ train_forward_KLXX_G,
90
+ )
91
+ ```
92
+
93
+ Every trainer returns a new flow and its optimizer-batch ESS history. Simple
94
+ flow, sample, and history serialization lives in `jflows.artifacts`.
95
+
96
+ ### HIGH — staged Boltzmann generation
97
+
98
+ The high level connects accepted bridge stages and compares every trained map
99
+ with an exact identity fallback using full-validation incremental ESS:
100
+
101
+ ```python
102
+ from jflows.boltzmann import (
103
+ boltzmann_identity,
104
+ boltzmann_reverse_KL_F,
105
+ boltzmann_forward_KL_G,
106
+ boltzmann_forward_KLX_G,
107
+ boltzmann_forward_KLXX_G,
108
+ )
109
+ ```
110
+
111
+ - identity runs the adaptive-staging controller for stage selection, ESS
112
+ gating, resampling, and rejuvenation with no flow or optimizer;
113
+ - reverse KL is the simplest source-sampled F baseline;
114
+ - forward KL manufactures target-side batches and trains G;
115
+ - KLX adds target-measure log-weight variation control; and
116
+ - KLXX adds a quench-and-temper/proposal mixture for wider mode and leakage
117
+ regularization.
118
+
119
+ The four trained generators compare their candidate with identity. The
120
+ standalone `boltzmann_identity` function instead advances every accepted
121
+ stage by exact identity reweighting, so it requires no flow, batch size,
122
+ training steps, or learning rate. Complete-stage persistence is exposed
123
+ separately through `jflows.boltzmann.write` and `jflows.boltzmann.load`.
124
+
125
+ ## Minimal setup
126
+
127
+ ```bash
128
+ pip install "jax[cuda13]" equinox
129
+ pip install -e .
130
+ ```
131
+
132
+ ```python
133
+ import jflows
134
+
135
+ jflows.backend()
136
+ ```
137
+
138
+ A minimal training setup is:
139
+
140
+ ```python
141
+ import jax
142
+
143
+ from jflows.flow import NSF
144
+ from jflows.potential import Nlog_Gaussian, potential_from
145
+ from jflows.train import train_forward_KLX_G
146
+ from jflows.utils import compute_ESS_log, importance_weights_log
147
+
148
+ source = Nlog_Gaussian([0.0, 0.0], [1.0, 1.0])
149
+ target = potential_from(
150
+ lambda x: 10.0 * (jax.numpy.linalg.norm(x, axis=-1) - 2.0) ** 2
151
+ )
152
+
153
+ flow = NSF(
154
+ jax.random.key(0),
155
+ [-4.0, -4.0],
156
+ [4.0, 4.0],
157
+ bins=16,
158
+ transforms=4,
159
+ ).zeros()
160
+ x_valid = source.samples(jax.random.key(1), 20000)
161
+
162
+ flow, batch_ess = train_forward_KLX_G(
163
+ x_valid,
164
+ source,
165
+ target,
166
+ flow,
167
+ batch_size=500,
168
+ train_steps=200,
169
+ lr=1e-3,
170
+ ladder=1,
171
+ mc_dt=1e-3,
172
+ mc_steps=50,
173
+ coeff_lambda=1.0,
174
+ )
175
+
176
+ log_weights = importance_weights_log(
177
+ x_valid, source, target, flow, type="G"
178
+ )
179
+ validation_ess = compute_ESS_log(log_weights)
180
+ y_valid = flow.inv(x_valid)
181
+ ```
182
+
183
+ ## Repository map
184
+
185
+ ```text
186
+ jflows/
187
+ ├── doc/
188
+ │ ├── README.md # detailed documentation map
189
+ │ ├── 01-low-level.md
190
+ │ ├── 02-medium-level.md
191
+ │ ├── 03-high-level.md
192
+ │ ├── 04-smoke-tests.md
193
+ │ └── 05-examples.md
194
+ ├── jflows/
195
+ │ ├── flow.py # LOW
196
+ │ ├── potential.py # LOW
197
+ │ ├── loss.py # LOW
198
+ │ ├── utils/ # LOW
199
+ │ ├── train.py # MEDIUM
200
+ │ ├── artifacts.py # MEDIUM
201
+ │ ├── boltzmann/ # HIGH
202
+ │ └── core/ # private implementation
203
+ ├── smoke/ # narrow executable contracts
204
+ ├── example/ # complete workflows and results
205
+ └── README.md # this concise project introduction
206
+ ```
207
+
208
+ ## Read next
209
+
210
+ - **Detailed interface documentation:** [`doc/`](doc/README.md)
211
+ - **Executable API contracts:** [`smoke/`](smoke/)
212
+ - **Complete scripts, figures, and numerical results:**
213
+ [`example/`](example/) and [`example/results.md`](example/results.md)
214
+
215
+ The detailed documentation gives exact signatures, direction conventions,
216
+ return values, memory controls, stage records, and persistence behavior. Smoke
217
+ tests establish narrow software contracts; examples demonstrate end-to-end
218
+ scientific workflows.
219
+
220
+ ## Acknowledgements
221
+
222
+ `jflows` is strongly inspired by [zuko](https://github.com/probabilists/zuko).
223
+ The private flow, transform, and masked-MLP machinery in `jflows.core` is a
224
+ stripped-down port of zuko's clean and composable transform design.
@@ -0,0 +1,93 @@
1
+ """jflows — JAX normalizing flows for unconditional energy-based sampling.
2
+
3
+ Built on JAX and equinox.
4
+
5
+ Public surface:
6
+
7
+ jflows.flow : Flow, NSF, NCSF, CNF, OTFlow, RealNVP, ComposedTransform
8
+ jflows.potential : Potential, potential_from, Nlog_Uniform, Nlog_Gaussian,
9
+ Nlog_Gaussian_Mixture, linear_combination (+ the operator
10
+ algebra c*U, U+V, U-V, -U, U/c, sum([...]))
11
+ jflows.loss : reverse_KL_F, forward_KL_G, forward_KLX_G,
12
+ forward_X_G
13
+ jflows.train : Monitor and all train_* stage drivers
14
+ jflows.boltzmann : adaptive-staging and fixed-schedule boltzmann_* generators
15
+ jflows.artifacts : save and load medium-level training outputs
16
+ jflows.backend : selected/available JAX backends and accelerator model
17
+ jflows.utils : metrics / optimization / rejuvenation / anneal / quench
18
+
19
+ Internals (`jflows.core.*`) adapt zuko's clean flow and transform design.
20
+ The public computation API uses explicit PRNG keys and takes `Flow` objects
21
+ directly for losses, importance weights, AIS, and training.
22
+ """
23
+
24
+ from importlib.metadata import entry_points
25
+ from importlib.util import find_spec
26
+ import os
27
+ from shutil import which
28
+ import subprocess
29
+
30
+ import equinox
31
+ import jax
32
+
33
+ from . import artifacts, boltzmann, flow, loss, potential, train, utils
34
+ from .version import __version__
35
+
36
+
37
+ def backend():
38
+ """Print the available JAX backends and selected accelerator."""
39
+ plugins = tuple(item.name.lower() for item in entry_points(group="jax_plugins"))
40
+ available = ["CPU"]
41
+ details = ["- CPU — cpu"]
42
+
43
+ cuda_visible = os.environ.get("CUDA_VISIBLE_DEVICES") not in ("", "-1")
44
+ if cuda_visible and any("cuda" in name for name in plugins) and which("nvidia-smi"):
45
+ result = subprocess.run(
46
+ ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
47
+ capture_output=True,
48
+ text=True,
49
+ )
50
+ models = tuple(
51
+ dict.fromkeys(line for line in result.stdout.splitlines() if line)
52
+ )
53
+ if result.returncode == 0 and models:
54
+ available.append("CUDA")
55
+ details.append(f"- CUDA — {', '.join(models)}")
56
+
57
+ rocm_visible = os.environ.get("ROCR_VISIBLE_DEVICES") not in ("", "-1")
58
+ if rocm_visible and any("rocm" in name for name in plugins) and which("rocm-smi"):
59
+ available.append("ROCm")
60
+ details.append("- ROCm")
61
+
62
+ if find_spec("libtpu"):
63
+ available.append("TPU")
64
+ details.append("- TPU")
65
+
66
+ configured = os.environ.get("JAX_PLATFORMS", "").split(",")[0].lower()
67
+ selected = {"cpu": "CPU", "cuda": "CUDA", "rocm": "ROCm", "tpu": "TPU"}.get(
68
+ configured
69
+ )
70
+ if selected not in available:
71
+ selected = next(
72
+ name for name in ("CUDA", "ROCm", "TPU", "CPU") if name in available
73
+ )
74
+
75
+ print(f"JAX {jax.__version__}")
76
+ print(f"Equinox {equinox.__version__}")
77
+ print(f"Selected backend: {selected}")
78
+ print(f"Available backends: {', '.join(available)}")
79
+ for detail in details:
80
+ print(detail)
81
+
82
+
83
+ __all__ = [
84
+ "__version__",
85
+ "artifacts",
86
+ "backend",
87
+ "boltzmann",
88
+ "flow",
89
+ "loss",
90
+ "potential",
91
+ "train",
92
+ "utils",
93
+ ]
@@ -0,0 +1,46 @@
1
+ """Save and load medium-level training outputs."""
2
+
3
+ from pathlib import Path
4
+
5
+ import equinox as eqx
6
+ import numpy as np
7
+
8
+ __all__ = [
9
+ "load_flow",
10
+ "load_history",
11
+ "load_samples",
12
+ "save_flow",
13
+ "save_history",
14
+ "save_samples",
15
+ ]
16
+
17
+
18
+ def save_flow(path, flow) -> None:
19
+ """Save one flow's array leaves."""
20
+ eqx.tree_serialise_leaves(Path(path), flow)
21
+
22
+
23
+ def load_flow(path, template):
24
+ """Load flow leaves into a matching template."""
25
+ return eqx.tree_deserialise_leaves(Path(path), template)
26
+
27
+
28
+ def save_samples(path, samples) -> None:
29
+ """Save one sample array."""
30
+ np.save(Path(path), np.asarray(samples), allow_pickle=False)
31
+
32
+
33
+ def load_samples(path):
34
+ """Load one sample array."""
35
+ return np.load(Path(path), allow_pickle=False)
36
+
37
+
38
+ def save_history(path, **history) -> None:
39
+ """Save named training-history arrays."""
40
+ np.savez(Path(path), **history)
41
+
42
+
43
+ def load_history(path) -> dict:
44
+ """Load named training-history arrays."""
45
+ with np.load(Path(path), allow_pickle=False) as history:
46
+ return {name: history[name].copy() for name in history.files}