openquantumsim 0.1.0a1__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 (59) hide show
  1. openquantumsim-0.1.0a1/CHANGELOG.md +29 -0
  2. openquantumsim-0.1.0a1/CITATION.cff +17 -0
  3. openquantumsim-0.1.0a1/CONTRIBUTING.md +39 -0
  4. openquantumsim-0.1.0a1/LICENSE +21 -0
  5. openquantumsim-0.1.0a1/MANIFEST.in +7 -0
  6. openquantumsim-0.1.0a1/PKG-INFO +427 -0
  7. openquantumsim-0.1.0a1/README.md +384 -0
  8. openquantumsim-0.1.0a1/openquantumsim/__init__.py +202 -0
  9. openquantumsim-0.1.0a1/openquantumsim/_julia_bridge.py +80 -0
  10. openquantumsim-0.1.0a1/openquantumsim/_version.py +3 -0
  11. openquantumsim-0.1.0a1/openquantumsim/correlations.py +144 -0
  12. openquantumsim-0.1.0a1/openquantumsim/hilbert.py +114 -0
  13. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/Manifest.toml +1644 -0
  14. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/Project.toml +26 -0
  15. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Correlations.jl +205 -0
  16. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/HilbertSpace.jl +51 -0
  17. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Lindblad.jl +155 -0
  18. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Observables.jl +78 -0
  19. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/OpenQuantumSimJL.jl +34 -0
  20. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Operators.jl +99 -0
  21. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Parallel.jl +1 -0
  22. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Propagators.jl +40 -0
  23. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/SteadyState.jl +61 -0
  24. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/TimeDep.jl +191 -0
  25. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Trajectories.jl +600 -0
  26. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/src/Utils.jl +1 -0
  27. openquantumsim-0.1.0a1/openquantumsim/julia/OpenQuantumSimJL/test/runtests.jl +497 -0
  28. openquantumsim-0.1.0a1/openquantumsim/observables.py +661 -0
  29. openquantumsim-0.1.0a1/openquantumsim/operators.py +462 -0
  30. openquantumsim-0.1.0a1/openquantumsim/phase_space.py +153 -0
  31. openquantumsim-0.1.0a1/openquantumsim/plot.py +210 -0
  32. openquantumsim-0.1.0a1/openquantumsim/py.typed +1 -0
  33. openquantumsim-0.1.0a1/openquantumsim/result.py +332 -0
  34. openquantumsim-0.1.0a1/openquantumsim/solvers.py +704 -0
  35. openquantumsim-0.1.0a1/openquantumsim/sweep.py +562 -0
  36. openquantumsim-0.1.0a1/openquantumsim/systems.py +136 -0
  37. openquantumsim-0.1.0a1/openquantumsim/timedep.py +162 -0
  38. openquantumsim-0.1.0a1/openquantumsim.egg-info/PKG-INFO +427 -0
  39. openquantumsim-0.1.0a1/openquantumsim.egg-info/SOURCES.txt +57 -0
  40. openquantumsim-0.1.0a1/openquantumsim.egg-info/dependency_links.txt +1 -0
  41. openquantumsim-0.1.0a1/openquantumsim.egg-info/requires.txt +24 -0
  42. openquantumsim-0.1.0a1/openquantumsim.egg-info/top_level.txt +1 -0
  43. openquantumsim-0.1.0a1/pyproject.toml +90 -0
  44. openquantumsim-0.1.0a1/setup.cfg +4 -0
  45. openquantumsim-0.1.0a1/tests/test_analyze_dicke_mi_distribution.py +101 -0
  46. openquantumsim-0.1.0a1/tests/test_bench_dicke_mi.py +81 -0
  47. openquantumsim-0.1.0a1/tests/test_docs.py +93 -0
  48. openquantumsim-0.1.0a1/tests/test_hilbert.py +26 -0
  49. openquantumsim-0.1.0a1/tests/test_observables.py +120 -0
  50. openquantumsim-0.1.0a1/tests/test_operators.py +158 -0
  51. openquantumsim-0.1.0a1/tests/test_packaging.py +42 -0
  52. openquantumsim-0.1.0a1/tests/test_phase_space.py +64 -0
  53. openquantumsim-0.1.0a1/tests/test_plot.py +47 -0
  54. openquantumsim-0.1.0a1/tests/test_result_io.py +150 -0
  55. openquantumsim-0.1.0a1/tests/test_run_dicke_mi_distribution.py +129 -0
  56. openquantumsim-0.1.0a1/tests/test_run_sweep.py +65 -0
  57. openquantumsim-0.1.0a1/tests/test_sweep.py +105 -0
  58. openquantumsim-0.1.0a1/tests/test_systems.py +62 -0
  59. openquantumsim-0.1.0a1/tests/test_timedep.py +55 -0
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ All notable changes to OpenQuantumSim will be documented here.
4
+
5
+ The project follows semantic versioning once the public API reaches `0.1.0`.
6
+ Until then, entries are grouped under alpha releases.
7
+
8
+ ## Unreleased
9
+
10
+ ## 0.1.0a1 - 2026-05-15
11
+
12
+ - Removed an invalid PyPI trove classifier from the package metadata so the
13
+ alpha can be published through TestPyPI/PyPI.
14
+ - Documented TestPyPI and PyPI trusted-publisher verification commands.
15
+
16
+ ## 0.1.0a0 - 2026-05-14
17
+
18
+ - Added a Python frontend and Julia backend package scaffold.
19
+ - Added dense Hilbert-space, state, and operator helpers.
20
+ - Added `mesolve`, `mcsolve`, and `single_trajectory` Python entry points.
21
+ - Added HDF5 result persistence and checkpointed MCWF runs.
22
+ - Added model-agnostic partial trace, entropy, purity, and mutual information
23
+ utilities.
24
+ - Added named scalar `state_observables` for `mesolve` and
25
+ `single_trajectory`.
26
+ - Moved the two-ensemble Dicke workflow into `examples/dicke` so the public
27
+ package remains model agnostic.
28
+ - Added release-hygiene files for citation, contribution, changelog, and
29
+ publish-readiness tracking.
@@ -0,0 +1,17 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use OpenQuantumSim, please cite the software release."
3
+ title: "OpenQuantumSim"
4
+ version: "0.1.0a1"
5
+ abstract: "Python-accessible, Julia-powered simulation tools for open quantum systems."
6
+ authors:
7
+ - family-names: "Jafari"
8
+ given-names: "Mohammad"
9
+ license: "MIT"
10
+ repository-code: "https://github.com/mohammadjafariph/OpenQuantumSimulation"
11
+ keywords:
12
+ - "open quantum systems"
13
+ - "Lindblad equation"
14
+ - "Monte Carlo wave function"
15
+ - "quantum trajectories"
16
+ - "Julia"
17
+ - "Python"
@@ -0,0 +1,39 @@
1
+ # Contributing
2
+
3
+ OpenQuantumSim is still pre-alpha, so the most useful contributions are small,
4
+ well-tested changes that make the public API clearer, more reliable, or easier
5
+ to install.
6
+
7
+ ## Development Setup
8
+
9
+ ```bash
10
+ python -m pip install -e ".[dev]"
11
+ python setup_julia.py
12
+ python -m pytest
13
+ ```
14
+
15
+ Run the Julia backend tests directly with:
16
+
17
+ ```bash
18
+ julia --project=src/OpenQuantumSimJL -e 'using Pkg; Pkg.test()'
19
+ ```
20
+
21
+ ## Checks Before A Pull Request
22
+
23
+ ```bash
24
+ python -m ruff check openquantumsim examples tests scripts benchmarks README.md
25
+ python -m mypy openquantumsim
26
+ python -m pytest
27
+ python scripts/check_publish_ready.py
28
+ ```
29
+
30
+ ## Contribution Guidelines
31
+
32
+ - Keep the `openquantumsim` package model agnostic. Specific physics studies
33
+ belong in `examples/` unless they are genuinely reusable library primitives.
34
+ - Add tests for public behavior changes.
35
+ - Keep Python and Julia backend changes synchronized. The packaged Julia
36
+ backend mirror under `openquantumsim/julia/OpenQuantumSimJL` must match the
37
+ development backend under `src/OpenQuantumSimJL`.
38
+ - Document new public API in the README or Sphinx docs.
39
+ - Avoid committing generated simulation outputs.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mohammad Jafari
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.
@@ -0,0 +1,7 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CITATION.cff
4
+ include CHANGELOG.md
5
+ include CONTRIBUTING.md
6
+ recursive-include openquantumsim/julia/OpenQuantumSimJL *.jl *.toml
7
+ include openquantumsim/py.typed
@@ -0,0 +1,427 @@
1
+ Metadata-Version: 2.4
2
+ Name: openquantumsim
3
+ Version: 0.1.0a1
4
+ Summary: Python-accessible, Julia-powered simulation tools for open quantum systems.
5
+ Author: Mohammad Jafari
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/mohammadjafariph/OpenQuantumSimulation
8
+ Project-URL: Issues, https://github.com/mohammadjafariph/OpenQuantumSimulation/issues
9
+ Project-URL: Documentation, https://github.com/mohammadjafariph/OpenQuantumSimulation#readme
10
+ Project-URL: Source, https://github.com/mohammadjafariph/OpenQuantumSimulation
11
+ Keywords: open quantum systems,quantum trajectories,lindblad,julia
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Physics
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=1.24
23
+ Requires-Dist: scipy>=1.10
24
+ Requires-Dist: juliacall>=0.9
25
+ Requires-Dist: h5py>=3.8
26
+ Requires-Dist: xarray>=2023.1
27
+ Requires-Dist: matplotlib>=3.7
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.4; extra == "dev"
30
+ Requires-Dist: pytest-cov>=4.1; extra == "dev"
31
+ Requires-Dist: mypy>=1.7; extra == "dev"
32
+ Requires-Dist: ruff>=0.1.8; extra == "dev"
33
+ Provides-Extra: docs
34
+ Requires-Dist: sphinx>=7.0; extra == "docs"
35
+ Requires-Dist: myst-parser>=2.0; extra == "docs"
36
+ Requires-Dist: myst-nb>=1.0; extra == "docs"
37
+ Provides-Extra: release
38
+ Requires-Dist: build>=1.2; extra == "release"
39
+ Requires-Dist: twine>=5.0; extra == "release"
40
+ Provides-Extra: validation
41
+ Requires-Dist: qutip>=5.0; extra == "validation"
42
+ Dynamic: license-file
43
+
44
+ # OpenQuantumSim
45
+
46
+ Python-accessible, Julia-powered tools for simulating open quantum systems.
47
+
48
+ OpenQuantumSim is starting as a research-grade package with a Python frontend
49
+ and a Julia backend. The first development target is a reliable MVP for
50
+ Lindblad master-equation propagation, Monte Carlo wave-function trajectories,
51
+ basic Hilbert-space construction, observables, and validation against canonical
52
+ open-system examples.
53
+
54
+ ## Current Status
55
+
56
+ This repository is a public alpha candidate. It is usable for development and
57
+ local research runs; release readiness is tracked in
58
+ `docs/release_checklist.md`. The current package includes:
59
+
60
+ - A Python package namespace: `openquantumsim`
61
+ - A Julia backend package: `OpenQuantumSimJL`
62
+ - Basic Hilbert-space types and dense Python operator primitives
63
+ - Sparse Julia operator and observable primitives
64
+ - Symmetric Dicke manifolds for collective spin ensembles
65
+ - General subsystem utilities such as `partial_trace` and mutual information
66
+ - Solver entry points for `mesolve`, time-dependent `mesolve`, `mcsolve`, and
67
+ `steadystate`
68
+ - Starter tests for Python and Julia
69
+ - Release metadata and package-data wiring for the Julia backend
70
+
71
+ ## Roadmap Focus
72
+
73
+ Phase 1 and Phase 2 follow the R&D roadmap:
74
+
75
+ 1. Implement `FockSpace`, `SpinSpace`, basic states, and operators.
76
+ 2. Build a `juliacall` bridge that loads `OpenQuantumSimJL`.
77
+ 3. Implement `mesolve` for time-independent Lindblad dynamics.
78
+ 4. Implement `mcsolve` for MCWF trajectories with thread-local RNG.
79
+ 5. Add sparse/Krylov propagation and composite-space observables.
80
+ 6. Add time-dependent Hamiltonians and parameter-sweep execution.
81
+ 7. Validate against qubit decay and Jaynes-Cummings reference results.
82
+
83
+ ## Quick Start
84
+
85
+ ```bash
86
+ python -m pip install -e .
87
+ python setup_julia.py
88
+ ```
89
+
90
+ The first Julia backend setup may spend a few minutes precompiling packages.
91
+ Then run a small spontaneous-emission smoke test:
92
+
93
+ ```bash
94
+ python - <<'PY'
95
+ import numpy as np
96
+ import openquantumsim as oqs
97
+
98
+ atom = oqs.SpinSpace(0.5, label="atom")
99
+ H = 0.0 * oqs.sigmaz(atom)
100
+ psi0 = oqs.basis(atom, "up")
101
+ rho0 = oqs.ket2dm(psi0)
102
+ gamma = 0.2
103
+ collapse = np.sqrt(gamma) * oqs.sigmam(atom)
104
+ projector = oqs.Operator(oqs.ket2dm(psi0), atom, "P_excited")
105
+ times = np.linspace(0.0, 0.2, 3)
106
+
107
+ result = oqs.mesolve(H, rho0, times, c_ops=[collapse], e_ops=[projector])
108
+ expected = np.exp(-gamma * times)
109
+ print(result.expect[0].real)
110
+ assert np.allclose(result.expect[0].real, expected, atol=2e-7)
111
+ PY
112
+ ```
113
+
114
+ For development checks, install the optional test tools and run:
115
+
116
+ ```bash
117
+ python -m pip install -e ".[dev]"
118
+ python -m pytest
119
+ ```
120
+
121
+ For the Julia backend:
122
+
123
+ ```bash
124
+ julia --project=src/OpenQuantumSimJL -e 'using Pkg; Pkg.test()'
125
+ ```
126
+
127
+ Build the local API docs and tutorial notebooks with:
128
+
129
+ ```bash
130
+ python -m pip install -e ".[docs]"
131
+ sphinx-build -b html docs docs/_build/html
132
+ ```
133
+
134
+ ## Benchmarks
135
+
136
+ The first benchmark harness measures Monte Carlo trajectory scaling for the
137
+ qubit decay validation problem:
138
+
139
+ ```bash
140
+ PYTHON_JULIACALL_HANDLE_SIGNALS=yes JULIA_NUM_THREADS=auto \
141
+ python benchmarks/bench_mcsolve.py --n-traj 1000 --repeats 3
142
+ ```
143
+
144
+ Use `scripts/run_benchmarks.sh` to run the default benchmark entry point. The
145
+ report includes Python elapsed time, Julia backend wall time, worker count, and
146
+ the maximum expectation-value delta from the serial reference.
147
+
148
+ The Dicke mutual-information research example has a separate batch benchmark:
149
+
150
+ ```bash
151
+ python examples/dicke/bench_mi.py \
152
+ --N 6 \
153
+ --n-traj 20 \
154
+ --time-points 101 \
155
+ --batch-size 5 \
156
+ --n-jobs 1 4 \
157
+ --target-n-traj 1000
158
+ ```
159
+
160
+ ## Production Runner
161
+
162
+ A checkpointed MCWF runner is available for the qubit-decay validation problem:
163
+
164
+ ```bash
165
+ python scripts/run_mcsolve_qubit_decay.py \
166
+ --n-traj 2000 \
167
+ --checkpoint-file runs/qubit_decay_checkpoint.h5 \
168
+ --output runs/qubit_decay.h5 \
169
+ --force
170
+ ```
171
+
172
+ The script resumes from an existing matching checkpoint, prints progress by
173
+ default, and saves the final solver result as HDF5.
174
+
175
+ ## Sweep Runner
176
+
177
+ The public `ParameterSweep` API expands parameter grids, skips completed
178
+ points on rerun, writes a restartable manifest, saves returned `Result`
179
+ objects, and produces aggregate `summary.csv` / `summary.h5` files:
180
+
181
+ ```python
182
+ sweep = oqs.ParameterSweep(
183
+ base_system={"model": "qubit_decay"},
184
+ params={"kappa": [0.02, 0.05, 0.1]},
185
+ )
186
+
187
+ run = sweep.run(run_one_point, output_dir="runs/kappa_sweep")
188
+ print(run.summary)
189
+ ```
190
+
191
+ The CLI wrapper uses the same output layout:
192
+
193
+ ```bash
194
+ python scripts/run_sweep.py \
195
+ --kappa-values 0.02,0.05,0.1 \
196
+ --n-traj 2000 \
197
+ --output-dir runs/kappa_sweep
198
+ ```
199
+
200
+ Re-running the same command skips completed points and resumes unfinished
201
+ checkpointed points.
202
+
203
+ Research examples live on top of the general solver API. The roadmap
204
+ two-ensemble Dicke study has its model builder and analysis scripts in
205
+ `examples/dicke/`.
206
+
207
+ Single trajectories can save kets for trajectory-level diagnostics:
208
+
209
+ ```python
210
+ import numpy as np
211
+ import openquantumsim as oqs
212
+ from examples.dicke.observables import trajectory_dicke_mutual_information
213
+ from examples.dicke.system import two_ensemble_dicke_system
214
+
215
+ system = two_ensemble_dicke_system(N=6, kappa=0.1)
216
+ times = np.linspace(0.0, 1.0, 101)
217
+
218
+ result = oqs.single_trajectory(
219
+ system.H,
220
+ system.psi0,
221
+ times,
222
+ c_ops=system.c_ops,
223
+ e_ops=system.e_ops,
224
+ options=oqs.Options(seed=2026, max_step=0.01, save_states=True),
225
+ )
226
+
227
+ mi_a, mi_b = trajectory_dicke_mutual_information(result.states or [], 6)
228
+ ```
229
+
230
+ For batched MI distributions, use the restartable trajectory runner:
231
+
232
+ ```bash
233
+ python examples/dicke/run_mi_distribution.py \
234
+ --n-values 6,8,12 \
235
+ --kappa-values 0.1 \
236
+ --n-traj 1000 \
237
+ --time-points 2001 \
238
+ --t-final 200 \
239
+ --n-jobs 4 \
240
+ --batch-size 10 \
241
+ --output runs/dicke_mi_distribution.h5
242
+ ```
243
+
244
+ The HDF5 output stores `MI_time_A`, `MI_time_B`, `MI_steady_A`, and
245
+ `MI_steady_B` under `kappa_<value>/N_<N>` groups and can resume incomplete
246
+ points from the stored trajectory count. Worker processes compute trajectory
247
+ batches; the parent process owns all HDF5 writes.
248
+
249
+ Summarize and plot completed MI distribution runs with:
250
+
251
+ ```bash
252
+ python examples/dicke/analyze_mi_distribution.py \
253
+ --input runs/dicke_mi_distribution.h5 \
254
+ --output-dir runs/dicke_mi_analysis
255
+ ```
256
+
257
+ The analyzer writes `summary.csv`, `summary.h5`, `steady_mi_mean.png`, and
258
+ `steady_mi_boxplot.png`.
259
+
260
+ The first recommended pilot settings are captured in `examples/dicke/README.md`.
261
+
262
+ ## Validation
263
+
264
+ Canonical validation cases currently cover analytic qubit decay and a
265
+ Jaynes-Cummings comparison against QuTiP. Install the optional validation extra
266
+ or QuTiP directly, then run:
267
+
268
+ ```bash
269
+ python scripts/validate_jaynes_cummings_qutip.py
270
+ ```
271
+
272
+ The script compares cavity photon number and atomic excited-state population
273
+ between OpenQuantumSim and QuTiP, and exits nonzero if the maximum deviation
274
+ exceeds the requested tolerance.
275
+
276
+ Two-time correlations use the quantum regression theorem for time-independent
277
+ Lindblad systems:
278
+
279
+ ```python
280
+ taus = np.linspace(0.0, 4.0, 101)
281
+ corr = oqs.correlation_2op_1t(
282
+ H,
283
+ rho0,
284
+ taus,
285
+ oqs.sigmap(qubit),
286
+ oqs.sigmam(qubit),
287
+ c_ops=[collapse],
288
+ )
289
+ ```
290
+
291
+ Finite Fock-space states can also be inspected in phase space:
292
+
293
+ ```python
294
+ x, p = oqs.phase_space_grid(xlim=(-5.0, 5.0), points=201)
295
+ rho = oqs.ket2dm(oqs.coherent(oqs.FockSpace(30), 1.0 + 0.5j))
296
+
297
+ W = oqs.wigner(rho, x, p)
298
+ Q = oqs.q_function(rho, x, p)
299
+ ax = oqs.plot_wigner(rho, x, p)
300
+ ```
301
+
302
+ ## Minimal Python Example
303
+
304
+ ```python
305
+ import numpy as np
306
+ import openquantumsim as oqs
307
+
308
+ qubit = oqs.SpinSpace(0.5, label="atom")
309
+ sm = oqs.sigmam(qubit)
310
+ H = 0.5 * oqs.sigmaz(qubit)
311
+ rho0 = oqs.ket2dm(oqs.basis(qubit, "up"))
312
+
313
+ print(H.shape)
314
+ print(np.trace(rho0))
315
+ ```
316
+
317
+ Subsystem observables are model agnostic:
318
+
319
+ ```python
320
+ bell = np.array([1, 0, 0, 1], dtype=np.complex128) / np.sqrt(2)
321
+ rho_a = oqs.partial_trace(bell, dims=(2, 2), keep=0)
322
+ mi_ab = oqs.mutual_information(bell, dims=(2, 2), subsystem_a=0, subsystem_b=1)
323
+ ```
324
+
325
+ Time-dependent Hamiltonians can be written as `H0 + sum_i f_i(t) H_i`:
326
+
327
+ ```python
328
+ drive = oqs.InterpolatedCoefficient([0.0, 5.0], [0.0, 0.2])
329
+ H_t = oqs.time_dependent_hamiltonian(
330
+ 0.5 * oqs.sigmaz(qubit),
331
+ [(oqs.sigmax(qubit), drive)],
332
+ )
333
+
334
+ result = oqs.mesolve(H_t, rho0, np.linspace(0.0, 5.0, 101))
335
+ ```
336
+
337
+ Collective open-system models can use a symmetric Dicke manifold instead of
338
+ the full `2**N` spin Hilbert space:
339
+
340
+ ```python
341
+ ensemble = oqs.DickeSpace(20, label="atoms")
342
+ Jm = oqs.collective_lowering(ensemble)
343
+ Jx = oqs.collective_x(ensemble)
344
+ Nexc = oqs.collective_excitation(ensemble)
345
+
346
+ H = 0.5 * Jx
347
+ c_ops = [np.sqrt(0.1 / ensemble.n_spins) * Jm]
348
+ psi0 = oqs.dicke_state(ensemble, excitations=ensemble.n_spins)
349
+ ```
350
+
351
+ Arbitrary scalar diagnostics can be evaluated from saved kets or density
352
+ matrices and persisted with the solver result:
353
+
354
+ For `mcsolve`, built-in diagnostics from `state_metrics` that are linear
355
+ expectations or pure-trajectory constants are aggregated in the Julia backend
356
+ with mean, standard deviation, and standard error.
357
+
358
+ ```python
359
+ metrics = oqs.state_metrics(
360
+ purity=True,
361
+ fidelity_to=psi0,
362
+ population_indices=[0, 1],
363
+ )
364
+ metrics["left_entropy"] = lambda ket: oqs.von_neumann_entropy(
365
+ oqs.partial_trace(ket, dims=(2, 2), keep=0)
366
+ )
367
+
368
+ result = oqs.single_trajectory(
369
+ H,
370
+ psi0,
371
+ times,
372
+ c_ops=c_ops,
373
+ state_observables=metrics,
374
+ options=oqs.Options(seed=2026, max_step=0.01),
375
+ )
376
+
377
+ left_entropy = result.state_observables["left_entropy"].real
378
+ return_fidelity = result.state_observables["fidelity"].real
379
+ ```
380
+
381
+ ## Result Persistence
382
+
383
+ Solver results can be saved in a portable HDF5 format:
384
+
385
+ ```python
386
+ result.save_hdf5("runs/qubit_decay.h5")
387
+ loaded = oqs.load_result("runs/qubit_decay.h5")
388
+ ```
389
+
390
+ The file stores time points, expectation series, optional saved states,
391
+ state-observable series, Monte Carlo uncertainty estimates, entropy, and solver
392
+ statistics. The full schema is documented in
393
+ `docs/result_hdf5_schema.rst`.
394
+
395
+ Long Monte Carlo trajectory runs can also checkpoint partial trajectory sums:
396
+
397
+ ```python
398
+ result = oqs.mcsolve(
399
+ H,
400
+ psi0,
401
+ times,
402
+ c_ops=[collapse],
403
+ e_ops=[observable],
404
+ n_traj=20_000,
405
+ options=oqs.Options(
406
+ seed=2026,
407
+ checkpoint_file="runs/mcsolve_checkpoint.h5",
408
+ checkpoint_every=100,
409
+ progress=True,
410
+ ),
411
+ )
412
+ ```
413
+
414
+ Calling `mcsolve` again with the same checkpoint file, seed, operators, time
415
+ grid, and `max_step` resumes from the stored trajectory count. Set
416
+ `progress=False` for silent batch runs.
417
+
418
+ ## Repository Layout
419
+
420
+ ```text
421
+ openquantumsim/ Python frontend
422
+ src/OpenQuantumSimJL/ Julia backend package
423
+ tests/ Python test suite
424
+ docs/ Sphinx documentation skeleton
425
+ benchmarks/ Benchmark scripts
426
+ scripts/ Development helpers
427
+ ```