quantum-playground 0.3.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 (44) hide show
  1. quantum_playground-0.3.0/LICENSE +21 -0
  2. quantum_playground-0.3.0/PKG-INFO +184 -0
  3. quantum_playground-0.3.0/README.md +156 -0
  4. quantum_playground-0.3.0/pyproject.toml +43 -0
  5. quantum_playground-0.3.0/setup.cfg +4 -0
  6. quantum_playground-0.3.0/src/qplay/__init__.py +29 -0
  7. quantum_playground-0.3.0/src/qplay/__main__.py +58 -0
  8. quantum_playground-0.3.0/src/qplay/animations.py +172 -0
  9. quantum_playground-0.3.0/src/qplay/atomic.py +86 -0
  10. quantum_playground-0.3.0/src/qplay/chaos.py +83 -0
  11. quantum_playground-0.3.0/src/qplay/circuits.py +75 -0
  12. quantum_playground-0.3.0/src/qplay/complexplane.py +41 -0
  13. quantum_playground-0.3.0/src/qplay/demos.py +464 -0
  14. quantum_playground-0.3.0/src/qplay/dynamics.py +71 -0
  15. quantum_playground-0.3.0/src/qplay/em.py +80 -0
  16. quantum_playground-0.3.0/src/qplay/hamiltonian.py +58 -0
  17. quantum_playground-0.3.0/src/qplay/integrators.py +67 -0
  18. quantum_playground-0.3.0/src/qplay/kinetic.py +163 -0
  19. quantum_playground-0.3.0/src/qplay/linalg.py +107 -0
  20. quantum_playground-0.3.0/src/qplay/mechanics.py +142 -0
  21. quantum_playground-0.3.0/src/qplay/nuclear.py +80 -0
  22. quantum_playground-0.3.0/src/qplay/numerics.py +85 -0
  23. quantum_playground-0.3.0/src/qplay/plotting.py +59 -0
  24. quantum_playground-0.3.0/src/qplay/quantum.py +294 -0
  25. quantum_playground-0.3.0/src/qplay/relativity.py +59 -0
  26. quantum_playground-0.3.0/src/qplay/statmech.py +53 -0
  27. quantum_playground-0.3.0/src/qplay/symbolic.py +57 -0
  28. quantum_playground-0.3.0/src/qplay/waves.py +87 -0
  29. quantum_playground-0.3.0/src/quantum_playground.egg-info/PKG-INFO +184 -0
  30. quantum_playground-0.3.0/src/quantum_playground.egg-info/SOURCES.txt +42 -0
  31. quantum_playground-0.3.0/src/quantum_playground.egg-info/dependency_links.txt +1 -0
  32. quantum_playground-0.3.0/src/quantum_playground.egg-info/entry_points.txt +2 -0
  33. quantum_playground-0.3.0/src/quantum_playground.egg-info/requires.txt +17 -0
  34. quantum_playground-0.3.0/src/quantum_playground.egg-info/top_level.txt +1 -0
  35. quantum_playground-0.3.0/tests/test_demos.py +51 -0
  36. quantum_playground-0.3.0/tests/test_explorer.py +253 -0
  37. quantum_playground-0.3.0/tests/test_extensions.py +297 -0
  38. quantum_playground-0.3.0/tests/test_maths.py +127 -0
  39. quantum_playground-0.3.0/tests/test_mechanics.py +80 -0
  40. quantum_playground-0.3.0/tests/test_new_physics.py +282 -0
  41. quantum_playground-0.3.0/tests/test_notebooks.py +55 -0
  42. quantum_playground-0.3.0/tests/test_quantum_relativity.py +95 -0
  43. quantum_playground-0.3.0/tests/test_site.py +44 -0
  44. quantum_playground-0.3.0/tests/test_waves_em.py +84 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 StativeSh
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,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantum-playground
3
+ Version: 0.3.0
4
+ Summary: A physics and maths playground: simulations, symbolic maths and notebooks.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://stativesh.github.io/quantum-playground/
7
+ Project-URL: Documentation, https://stativesh.github.io/quantum-playground/api/
8
+ Project-URL: Source, https://github.com/StativeSh/quantum-playground
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: numpy
13
+ Requires-Dist: scipy
14
+ Requires-Dist: sympy
15
+ Requires-Dist: matplotlib
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest; extra == "dev"
18
+ Requires-Dist: pytest-cov; extra == "dev"
19
+ Requires-Dist: jupyterlab; extra == "dev"
20
+ Requires-Dist: ipykernel; extra == "dev"
21
+ Requires-Dist: pandas; extra == "dev"
22
+ Requires-Dist: nbconvert; extra == "dev"
23
+ Requires-Dist: pdoc; extra == "dev"
24
+ Requires-Dist: build; extra == "dev"
25
+ Provides-Extra: browser
26
+ Requires-Dist: playwright; extra == "browser"
27
+ Dynamic: license-file
28
+
29
+ # quantum-playground
30
+
31
+ [![CI](https://github.com/StativeSh/quantum-playground/actions/workflows/ci.yml/badge.svg)](https://github.com/StativeSh/quantum-playground/actions/workflows/ci.yml)
32
+ [![Pages](https://github.com/StativeSh/quantum-playground/actions/workflows/pages.yml/badge.svg)](https://stativesh.github.io/quantum-playground/)
33
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
34
+
35
+ A physics and maths playground in Python: simulations, symbolic mechanics and Jupyter notebooks, with tests that check every solver against known analytic results.
36
+
37
+ **[Website](https://stativesh.github.io/quantum-playground/)**: every figure and animation, the executed notebooks and lessons, the [API reference](https://stativesh.github.io/quantum-playground/api/), and an [interactive explorer](https://stativesh.github.io/quantum-playground/explorer/) with live experiments: the pendulum, quantum tunnelling, the double slit, Kepler orbits, the Lorenz attractor and the Ising model.
38
+
39
+ <table>
40
+ <tr>
41
+ <td align="center"><img src="docs/images/double-slit.gif" width="260" alt="Wavepacket passing through two slits"><br><sub>Double slit: a 2D Schrödinger simulation</sub></td>
42
+ <td align="center"><img src="docs/images/double-pendulum.gif" width="260" alt="Chaotic double pendulum"><br><sub>Chaotic double pendulum</sub></td>
43
+ <td align="center"><img src="docs/images/figure-eight.gif" width="260" alt="Three-body figure-eight orbit"><br><sub>Three-body figure-eight orbit</sub></td>
44
+ </tr>
45
+ </table>
46
+
47
+ <img src="docs/images/wavepacket.gif" width="100%" alt="Wavepacket tunnelling through a barrier">
48
+
49
+ | | |
50
+ |---|---|
51
+ | ![Hydrogen orbitals](docs/images/hydrogen.png) | ![Double-slit fringes against theory](docs/images/double-slit.png) |
52
+ | Hydrogen orbitals $\lvert\psi_{nlm}\rvert$ | Double-slit fringes against the two-source prediction |
53
+ | ![Ising model](docs/images/ising.png) | ![Phase portraits](docs/images/phase-portrait.png) |
54
+ | 2D Ising model against Onsager's exact result | Phase portraits with classified fixed points |
55
+ | ![Mandelbrot set](docs/images/mandelbrot.png) | ![Domain colouring](docs/images/domain-coloring.png) |
56
+ | Mandelbrot set | Domain colouring and the argument principle |
57
+
58
+ ## Quick start
59
+
60
+ ```bash
61
+ make install # venv + editable install + Jupyter kernel
62
+ make test # run the test suite
63
+ make demos # render every demo figure into ./figures
64
+ make animations # render every GIF into ./figures
65
+ make lab # open JupyterLab
66
+ ```
67
+
68
+ Or without `make`:
69
+
70
+ ```bash
71
+ python3 -m venv .venv
72
+ .venv/bin/pip install -r requirements.txt
73
+ .venv/bin/qplay list
74
+ .venv/bin/qplay run pendulum wavepacket mandelbrot
75
+ ```
76
+
77
+ ## What is in the box
78
+
79
+ | Module | Topics |
80
+ |---|---|
81
+ | `qplay.mechanics` | damped/driven oscillator, nonlinear and double pendulum, projectile with drag, N-body gravity (figure-eight orbit) |
82
+ | `qplay.waves` | 1D wave equation, heat equation (Crank-Nicolson), Fourier series, spectra |
83
+ | `qplay.em` | point-charge fields, Laplace solver, charged particle in $\mathbf E$ and $\mathbf B$ fields |
84
+ | `qplay.quantum` | Schrödinger eigenstates for any 1D potential, split-step dynamics in 1D and 2D with absorbing edges, tunnelling, the double-slit experiment, hydrogen orbitals $R_{nl}Y_l^m$, spin-1/2, oscillator eigenstates and coherent states |
85
+ | `qplay.atomic` | angular momentum matrices, spin-orbit coupling, Zeeman effect from Landé $g_J$ to Paschen-Back, hydrogen fine structure against the Dirac energy |
86
+ | `qplay.kinetic` | hard-sphere gas in a box: Maxwell-Boltzmann distribution emerging from collisions, pressure from wall impulses, $pV = Nk_BT$ with the hard-sphere correction |
87
+ | `qplay.nuclear` | half-life, Bateman decay chains, matrix-exponential chains, Monte Carlo decay |
88
+ | `qplay.circuits` | RC charging and discharging, series RLC circuit, impedance, resonance and $Q$ factor |
89
+ | `qplay.statmech` | 2D Ising model (Metropolis), Onsager's exact magnetisation and $T_c = 2/\ln(1+\sqrt2)$ |
90
+ | `qplay.relativity` | time dilation, length contraction, velocity addition, Lorentz boosts |
91
+ | `qplay.chaos` | Lorenz system, logistic map, Lyapunov exponent, Mandelbrot and Julia sets |
92
+ | `qplay.symbolic` | SymPy: Lagrangian $\to$ Euler-Lagrange equations $\to$ runnable simulation |
93
+ | `qplay.hamiltonian` | Legendre transform, Hamilton's equations, Hamiltonian $\to$ runnable simulation |
94
+ | `qplay.dynamics` | phase portraits with automatically classified fixed points (saddle, node, spiral, center) |
95
+ | `qplay.complexplane` | domain colouring, argument principle (zeros $-$ poles from a winding number) |
96
+ | `qplay.linalg` | Gram-Schmidt, power iteration, how a matrix maps the unit circle (SVD) |
97
+ | `qplay.numerics` | bisection, Newton, Simpson, finite differences, Monte Carlo |
98
+ | `qplay.integrators` | Euler, RK4, velocity Verlet, adaptive wrapper |
99
+
100
+ ## Notebooks
101
+
102
+ | Notebook | Contents |
103
+ |---|---|
104
+ | `01_classical_mechanics` | period vs amplitude, double-pendulum chaos, deriving equations of motion symbolically |
105
+ | `02_quantum_mechanics` | oscillator and double-well states, tunnelling, wavepackets, Rabi oscillations |
106
+ | `03_maths_and_chaos` | Newton's method, Gibbs phenomenon, bifurcation diagram, fractals |
107
+ | `04_orbitals_interference_and_phase_space` | hydrogen orbitals, double slit, Ising phase transition, Legendre transform, phase planes, complex functions, linear maps |
108
+
109
+ ## Lessons for A-level and IB
110
+
111
+ Guided lessons in `lessons/`, each mapped to specification points, with exam-style questions that check your answers and worked solutions at the end. Every lesson and notebook has an **Open in Colab** button, so it runs in a browser with nothing to install.
112
+
113
+ Each lesson opens by saying which earlier lessons it builds on (and why) and which it leads to. Suggested routes:
114
+
115
+ | Route | Lessons, in order |
116
+ |---|---|
117
+ | Mechanics | 2 projectile motion → 3 circular motion and orbits → 1 simple harmonic motion |
118
+ | Waves to quantum | 1 simple harmonic motion → 4 stationary waves → 7 wave–particle duality |
119
+ | Fields | 3 circular motion and orbits → 5 electric fields → 6 charged particles in fields |
120
+ | Modern physics | 5 electric fields → 7 wave–particle duality → 8 special relativity |
121
+ | Thermal physics | 3 circular motion and orbits → 9 ideal gases and kinetic theory |
122
+
123
+ The prerequisites and routes live in `lessons/path.json`; `python scripts/lesson_path.py --write` copies them into the lesson headers, and the tests check that the two agree.
124
+
125
+ | Lesson | Covers |
126
+ |---|---|
127
+ | [`01_simple_harmonic_motion`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/01_simple_harmonic_motion.ipynb) | SHM equations and phase, spring and pendulum periods, energy, damping, resonance |
128
+ | [`02_projectile_motion`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/02_projectile_motion.ipynb) | independent horizontal and vertical motion, resolving velocity, time of flight, range and the 45° rule, launches from a height, air resistance |
129
+ | [`03_circular_motion_and_orbits`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/03_circular_motion_and_orbits.ipynb) | centripetal acceleration, orbital speed and period, geostationary orbits, Kepler's third law on a log-log plot, orbital energy and escape velocity |
130
+ | [`04_stationary_waves`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/04_stationary_waves.ipynb) | nodes and antinodes, harmonics on a string, why a plucked string is missing some harmonics, open and closed pipes, Fourier series |
131
+ | [`05_electric_fields`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/05_electric_fields.ipynb) | Coulomb's law, field lines and equipotentials, $E = -dV/dr$, uniform fields between plates and edge effects |
132
+ | [`06_charged_particles_in_fields`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/06_charged_particles_in_fields.ipynb) | parabolic paths in $E$, circles in $B$ with $r = mv/BQ$, cyclotron period, velocity selector, mass spectrometer, helices |
133
+ | [`07_wave_particle_duality`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/07_wave_particle_duality.ipynb) | photoelectric effect, Young's double slit, de Broglie wavelength, a simulated electron through two slits, building the pattern one particle at a time |
134
+ | [`08_special_relativity`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/08_special_relativity.ipynb) | postulates, time dilation and the muon experiment, length contraction, velocity addition, relativity of simultaneity, $E = \gamma mc^2$ |
135
+ | [`09_ideal_gases_and_kinetic_theory`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/09_ideal_gases_and_kinetic_theory.ipynb) | gas laws, a simulated gas relaxing to Maxwell-Boltzmann, pressure from collisions, temperature as molecular kinetic energy, when gases stop being ideal |
136
+
137
+ ## Demos and animations
138
+
139
+ `qplay list` shows everything. Twenty-five static figures (`qplay run NAME`), including `hydrogen`, `double-slit`, `ising`, `maxwell-boltzmann`, `coherent-state`, `zeeman`, `decay-chain` and `rlc-resonance`, and six GIFs (`qplay animate NAME`): `double-pendulum`, `wavepacket`, `figure-eight`, `double-slit`, `ising` and `gas`.
140
+
141
+ ## Example
142
+
143
+ Derive the equation of motion of a pendulum from its Lagrangian $L = \tfrac12 m\ell^2\dot\theta^2 + mg\ell\cos\theta$, then simulate it:
144
+
145
+ ```python
146
+ import sympy as sp
147
+ from qplay import symbolic, integrators
148
+
149
+ t, m, l, g = sp.symbols("t m l g", positive=True)
150
+ th = sp.Function("theta")(t)
151
+ L = m * l**2 * sp.diff(th, t)**2 / 2 + m * g * l * sp.cos(th)
152
+
153
+ symbolic.accelerations(L, [th], t) # [-g*sin(theta)/l]
154
+ rhs = symbolic.to_numeric_rhs(L, [th], t, {m: 1, l: 1, g: 9.81})
155
+ t_arr, y = integrators.solve(rhs, [1.0, 0.0], (0, 10))
156
+ ```
157
+
158
+ ## Adding a demo
159
+
160
+ ```python
161
+ # src/qplay/demos.py
162
+ @demo("my-demo")
163
+ def my_demo():
164
+ """One-line description shown by `qplay list`."""
165
+ fig, ax = plt.subplots()
166
+ ...
167
+ return fig
168
+ ```
169
+
170
+ It appears in `qplay list` and is covered by the test suite automatically. Animations work the same way with `@animation("name")` in `src/qplay/animations.py`, returning `(fig, update, frames)`.
171
+
172
+ ## Development
173
+
174
+ See `CLAUDE.md` for conventions.
175
+
176
+ - `make test` is the fast loop: it skips tests marked `slow` (the site build, the biggest simulations and the browser tests). `make test-all` runs everything, and `make coverage` adds a line-by-line coverage report that fails below 95%.
177
+ - `tests/test_explorer.py` drives the explorer in headless Chromium: it moves sliders and checks every readout against the Python package or an analytic formula, and lets the animations run to check what they converge to (orbital period, Lorenz separation, Ising magnetisation). Install with `pip install -e ".[browser]"` and `python -m playwright install chromium`, then `make test-browser`. Without Playwright these tests are skipped; CI installs it and fails if the browser is missing.
178
+ - CI runs every test with coverage on Python 3.10, 3.12 and 3.13, and executes the notebooks and lessons.
179
+ - The website is built by `.github/workflows/pages.yml` on every push to `main`: `scripts/build_site.py` renders all demos and animations, executes the notebooks to HTML, builds the API reference from the docstrings with pdoc, and copies the explorer from `site_src/`. Build it locally with `make site` (output in `_site/`), or just the API reference with `make api`. The README images live in `docs/images/` and are regenerated with `make readme-media`.
180
+ - Releases: the distribution is called `quantum-playground` (the import name is still `qplay`; the name `qplay` is taken on PyPI). Pushing a tag such as `v0.3.0` runs `.github/workflows/release.yml`, which checks the tag matches `qplay.__version__`, runs the tests, builds the wheel and publishes it to PyPI through a trusted publisher. `make dist` builds the same files locally.
181
+
182
+ ## License
183
+
184
+ MIT, see `LICENSE`.
@@ -0,0 +1,156 @@
1
+ # quantum-playground
2
+
3
+ [![CI](https://github.com/StativeSh/quantum-playground/actions/workflows/ci.yml/badge.svg)](https://github.com/StativeSh/quantum-playground/actions/workflows/ci.yml)
4
+ [![Pages](https://github.com/StativeSh/quantum-playground/actions/workflows/pages.yml/badge.svg)](https://stativesh.github.io/quantum-playground/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ A physics and maths playground in Python: simulations, symbolic mechanics and Jupyter notebooks, with tests that check every solver against known analytic results.
8
+
9
+ **[Website](https://stativesh.github.io/quantum-playground/)**: every figure and animation, the executed notebooks and lessons, the [API reference](https://stativesh.github.io/quantum-playground/api/), and an [interactive explorer](https://stativesh.github.io/quantum-playground/explorer/) with live experiments: the pendulum, quantum tunnelling, the double slit, Kepler orbits, the Lorenz attractor and the Ising model.
10
+
11
+ <table>
12
+ <tr>
13
+ <td align="center"><img src="docs/images/double-slit.gif" width="260" alt="Wavepacket passing through two slits"><br><sub>Double slit: a 2D Schrödinger simulation</sub></td>
14
+ <td align="center"><img src="docs/images/double-pendulum.gif" width="260" alt="Chaotic double pendulum"><br><sub>Chaotic double pendulum</sub></td>
15
+ <td align="center"><img src="docs/images/figure-eight.gif" width="260" alt="Three-body figure-eight orbit"><br><sub>Three-body figure-eight orbit</sub></td>
16
+ </tr>
17
+ </table>
18
+
19
+ <img src="docs/images/wavepacket.gif" width="100%" alt="Wavepacket tunnelling through a barrier">
20
+
21
+ | | |
22
+ |---|---|
23
+ | ![Hydrogen orbitals](docs/images/hydrogen.png) | ![Double-slit fringes against theory](docs/images/double-slit.png) |
24
+ | Hydrogen orbitals $\lvert\psi_{nlm}\rvert$ | Double-slit fringes against the two-source prediction |
25
+ | ![Ising model](docs/images/ising.png) | ![Phase portraits](docs/images/phase-portrait.png) |
26
+ | 2D Ising model against Onsager's exact result | Phase portraits with classified fixed points |
27
+ | ![Mandelbrot set](docs/images/mandelbrot.png) | ![Domain colouring](docs/images/domain-coloring.png) |
28
+ | Mandelbrot set | Domain colouring and the argument principle |
29
+
30
+ ## Quick start
31
+
32
+ ```bash
33
+ make install # venv + editable install + Jupyter kernel
34
+ make test # run the test suite
35
+ make demos # render every demo figure into ./figures
36
+ make animations # render every GIF into ./figures
37
+ make lab # open JupyterLab
38
+ ```
39
+
40
+ Or without `make`:
41
+
42
+ ```bash
43
+ python3 -m venv .venv
44
+ .venv/bin/pip install -r requirements.txt
45
+ .venv/bin/qplay list
46
+ .venv/bin/qplay run pendulum wavepacket mandelbrot
47
+ ```
48
+
49
+ ## What is in the box
50
+
51
+ | Module | Topics |
52
+ |---|---|
53
+ | `qplay.mechanics` | damped/driven oscillator, nonlinear and double pendulum, projectile with drag, N-body gravity (figure-eight orbit) |
54
+ | `qplay.waves` | 1D wave equation, heat equation (Crank-Nicolson), Fourier series, spectra |
55
+ | `qplay.em` | point-charge fields, Laplace solver, charged particle in $\mathbf E$ and $\mathbf B$ fields |
56
+ | `qplay.quantum` | Schrödinger eigenstates for any 1D potential, split-step dynamics in 1D and 2D with absorbing edges, tunnelling, the double-slit experiment, hydrogen orbitals $R_{nl}Y_l^m$, spin-1/2, oscillator eigenstates and coherent states |
57
+ | `qplay.atomic` | angular momentum matrices, spin-orbit coupling, Zeeman effect from Landé $g_J$ to Paschen-Back, hydrogen fine structure against the Dirac energy |
58
+ | `qplay.kinetic` | hard-sphere gas in a box: Maxwell-Boltzmann distribution emerging from collisions, pressure from wall impulses, $pV = Nk_BT$ with the hard-sphere correction |
59
+ | `qplay.nuclear` | half-life, Bateman decay chains, matrix-exponential chains, Monte Carlo decay |
60
+ | `qplay.circuits` | RC charging and discharging, series RLC circuit, impedance, resonance and $Q$ factor |
61
+ | `qplay.statmech` | 2D Ising model (Metropolis), Onsager's exact magnetisation and $T_c = 2/\ln(1+\sqrt2)$ |
62
+ | `qplay.relativity` | time dilation, length contraction, velocity addition, Lorentz boosts |
63
+ | `qplay.chaos` | Lorenz system, logistic map, Lyapunov exponent, Mandelbrot and Julia sets |
64
+ | `qplay.symbolic` | SymPy: Lagrangian $\to$ Euler-Lagrange equations $\to$ runnable simulation |
65
+ | `qplay.hamiltonian` | Legendre transform, Hamilton's equations, Hamiltonian $\to$ runnable simulation |
66
+ | `qplay.dynamics` | phase portraits with automatically classified fixed points (saddle, node, spiral, center) |
67
+ | `qplay.complexplane` | domain colouring, argument principle (zeros $-$ poles from a winding number) |
68
+ | `qplay.linalg` | Gram-Schmidt, power iteration, how a matrix maps the unit circle (SVD) |
69
+ | `qplay.numerics` | bisection, Newton, Simpson, finite differences, Monte Carlo |
70
+ | `qplay.integrators` | Euler, RK4, velocity Verlet, adaptive wrapper |
71
+
72
+ ## Notebooks
73
+
74
+ | Notebook | Contents |
75
+ |---|---|
76
+ | `01_classical_mechanics` | period vs amplitude, double-pendulum chaos, deriving equations of motion symbolically |
77
+ | `02_quantum_mechanics` | oscillator and double-well states, tunnelling, wavepackets, Rabi oscillations |
78
+ | `03_maths_and_chaos` | Newton's method, Gibbs phenomenon, bifurcation diagram, fractals |
79
+ | `04_orbitals_interference_and_phase_space` | hydrogen orbitals, double slit, Ising phase transition, Legendre transform, phase planes, complex functions, linear maps |
80
+
81
+ ## Lessons for A-level and IB
82
+
83
+ Guided lessons in `lessons/`, each mapped to specification points, with exam-style questions that check your answers and worked solutions at the end. Every lesson and notebook has an **Open in Colab** button, so it runs in a browser with nothing to install.
84
+
85
+ Each lesson opens by saying which earlier lessons it builds on (and why) and which it leads to. Suggested routes:
86
+
87
+ | Route | Lessons, in order |
88
+ |---|---|
89
+ | Mechanics | 2 projectile motion → 3 circular motion and orbits → 1 simple harmonic motion |
90
+ | Waves to quantum | 1 simple harmonic motion → 4 stationary waves → 7 wave–particle duality |
91
+ | Fields | 3 circular motion and orbits → 5 electric fields → 6 charged particles in fields |
92
+ | Modern physics | 5 electric fields → 7 wave–particle duality → 8 special relativity |
93
+ | Thermal physics | 3 circular motion and orbits → 9 ideal gases and kinetic theory |
94
+
95
+ The prerequisites and routes live in `lessons/path.json`; `python scripts/lesson_path.py --write` copies them into the lesson headers, and the tests check that the two agree.
96
+
97
+ | Lesson | Covers |
98
+ |---|---|
99
+ | [`01_simple_harmonic_motion`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/01_simple_harmonic_motion.ipynb) | SHM equations and phase, spring and pendulum periods, energy, damping, resonance |
100
+ | [`02_projectile_motion`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/02_projectile_motion.ipynb) | independent horizontal and vertical motion, resolving velocity, time of flight, range and the 45° rule, launches from a height, air resistance |
101
+ | [`03_circular_motion_and_orbits`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/03_circular_motion_and_orbits.ipynb) | centripetal acceleration, orbital speed and period, geostationary orbits, Kepler's third law on a log-log plot, orbital energy and escape velocity |
102
+ | [`04_stationary_waves`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/04_stationary_waves.ipynb) | nodes and antinodes, harmonics on a string, why a plucked string is missing some harmonics, open and closed pipes, Fourier series |
103
+ | [`05_electric_fields`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/05_electric_fields.ipynb) | Coulomb's law, field lines and equipotentials, $E = -dV/dr$, uniform fields between plates and edge effects |
104
+ | [`06_charged_particles_in_fields`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/06_charged_particles_in_fields.ipynb) | parabolic paths in $E$, circles in $B$ with $r = mv/BQ$, cyclotron period, velocity selector, mass spectrometer, helices |
105
+ | [`07_wave_particle_duality`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/07_wave_particle_duality.ipynb) | photoelectric effect, Young's double slit, de Broglie wavelength, a simulated electron through two slits, building the pattern one particle at a time |
106
+ | [`08_special_relativity`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/08_special_relativity.ipynb) | postulates, time dilation and the muon experiment, length contraction, velocity addition, relativity of simultaneity, $E = \gamma mc^2$ |
107
+ | [`09_ideal_gases_and_kinetic_theory`](https://colab.research.google.com/github/StativeSh/quantum-playground/blob/main/lessons/09_ideal_gases_and_kinetic_theory.ipynb) | gas laws, a simulated gas relaxing to Maxwell-Boltzmann, pressure from collisions, temperature as molecular kinetic energy, when gases stop being ideal |
108
+
109
+ ## Demos and animations
110
+
111
+ `qplay list` shows everything. Twenty-five static figures (`qplay run NAME`), including `hydrogen`, `double-slit`, `ising`, `maxwell-boltzmann`, `coherent-state`, `zeeman`, `decay-chain` and `rlc-resonance`, and six GIFs (`qplay animate NAME`): `double-pendulum`, `wavepacket`, `figure-eight`, `double-slit`, `ising` and `gas`.
112
+
113
+ ## Example
114
+
115
+ Derive the equation of motion of a pendulum from its Lagrangian $L = \tfrac12 m\ell^2\dot\theta^2 + mg\ell\cos\theta$, then simulate it:
116
+
117
+ ```python
118
+ import sympy as sp
119
+ from qplay import symbolic, integrators
120
+
121
+ t, m, l, g = sp.symbols("t m l g", positive=True)
122
+ th = sp.Function("theta")(t)
123
+ L = m * l**2 * sp.diff(th, t)**2 / 2 + m * g * l * sp.cos(th)
124
+
125
+ symbolic.accelerations(L, [th], t) # [-g*sin(theta)/l]
126
+ rhs = symbolic.to_numeric_rhs(L, [th], t, {m: 1, l: 1, g: 9.81})
127
+ t_arr, y = integrators.solve(rhs, [1.0, 0.0], (0, 10))
128
+ ```
129
+
130
+ ## Adding a demo
131
+
132
+ ```python
133
+ # src/qplay/demos.py
134
+ @demo("my-demo")
135
+ def my_demo():
136
+ """One-line description shown by `qplay list`."""
137
+ fig, ax = plt.subplots()
138
+ ...
139
+ return fig
140
+ ```
141
+
142
+ It appears in `qplay list` and is covered by the test suite automatically. Animations work the same way with `@animation("name")` in `src/qplay/animations.py`, returning `(fig, update, frames)`.
143
+
144
+ ## Development
145
+
146
+ See `CLAUDE.md` for conventions.
147
+
148
+ - `make test` is the fast loop: it skips tests marked `slow` (the site build, the biggest simulations and the browser tests). `make test-all` runs everything, and `make coverage` adds a line-by-line coverage report that fails below 95%.
149
+ - `tests/test_explorer.py` drives the explorer in headless Chromium: it moves sliders and checks every readout against the Python package or an analytic formula, and lets the animations run to check what they converge to (orbital period, Lorenz separation, Ising magnetisation). Install with `pip install -e ".[browser]"` and `python -m playwright install chromium`, then `make test-browser`. Without Playwright these tests are skipped; CI installs it and fails if the browser is missing.
150
+ - CI runs every test with coverage on Python 3.10, 3.12 and 3.13, and executes the notebooks and lessons.
151
+ - The website is built by `.github/workflows/pages.yml` on every push to `main`: `scripts/build_site.py` renders all demos and animations, executes the notebooks to HTML, builds the API reference from the docstrings with pdoc, and copies the explorer from `site_src/`. Build it locally with `make site` (output in `_site/`), or just the API reference with `make api`. The README images live in `docs/images/` and are regenerated with `make readme-media`.
152
+ - Releases: the distribution is called `quantum-playground` (the import name is still `qplay`; the name `qplay` is taken on PyPI). Pushing a tag such as `v0.3.0` runs `.github/workflows/release.yml`, which checks the tag matches `qplay.__version__`, runs the tests, builds the wheel and publishes it to PyPI through a trusted publisher. `make dist` builds the same files locally.
153
+
154
+ ## License
155
+
156
+ MIT, see `LICENSE`.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "quantum-playground"
7
+ version = "0.3.0"
8
+ description = "A physics and maths playground: simulations, symbolic maths and notebooks."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ dependencies = ["numpy", "scipy", "sympy", "matplotlib"]
14
+
15
+ [project.optional-dependencies]
16
+ dev = ["pytest", "pytest-cov", "jupyterlab", "ipykernel", "pandas", "nbconvert", "pdoc", "build"]
17
+ # Browser tests of the explorer (tests/test_explorer.py); also run `python -m playwright install chromium`.
18
+ browser = ["playwright"]
19
+
20
+ [project.urls]
21
+ Homepage = "https://stativesh.github.io/quantum-playground/"
22
+ Documentation = "https://stativesh.github.io/quantum-playground/api/"
23
+ Source = "https://github.com/StativeSh/quantum-playground"
24
+
25
+ [project.scripts]
26
+ qplay = "qplay.__main__:main"
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
30
+
31
+ [tool.pytest.ini_options]
32
+ testpaths = ["tests"]
33
+ # Slow tests (site build, big simulations) are skipped by default; `make test-all` or `pytest -m ""` runs them.
34
+ addopts = "-q -m 'not slow'"
35
+ markers = ["slow: takes more than a couple of seconds; skipped unless selected with -m \"\" or -m slow"]
36
+
37
+ [tool.coverage.run]
38
+ source = ["qplay"]
39
+
40
+ [tool.coverage.report]
41
+ fail_under = 95
42
+ show_missing = true
43
+ skip_covered = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ """qplay: a small physics and maths playground.
2
+
3
+ Modules
4
+ -------
5
+ integrators time-stepping schemes (Euler, RK4, velocity Verlet, adaptive wrapper)
6
+ mechanics oscillators, pendulums, projectiles, N-body gravity
7
+ waves 1D wave and heat equations, Fourier series, spectra
8
+ em point-charge fields, Laplace solver, charged-particle motion
9
+ quantum Schroedinger solvers (1D and 2D), tunnelling, double slit, hydrogen orbitals, spin-1/2,
10
+ oscillator eigenstates and coherent states
11
+ statmech 2D Ising model and Onsager's exact solution
12
+ relativity Lorentz transformations and special-relativity helpers
13
+ kinetic hard-sphere gas, Maxwell-Boltzmann distribution, ideal-gas law
14
+ atomic angular momentum, spin-orbit coupling, Zeeman effect, hydrogen fine structure
15
+ nuclear radioactive decay, Bateman decay chains, Monte Carlo decay
16
+ circuits RC charging and discharging, series RLC resonance
17
+ chaos Lorenz system, logistic map, Mandelbrot/Julia sets
18
+ symbolic SymPy helpers: Euler-Lagrange equations, Lagrangian -> simulation
19
+ hamiltonian Legendre transform, Hamilton's equations, Hamiltonian -> simulation
20
+ dynamics phase portraits and fixed-point classification for 2D systems
21
+ complexplane domain colouring and the argument principle
22
+ linalg Gram-Schmidt, power iteration, how a matrix maps the unit circle
23
+ numerics root finding, quadrature, finite differences, Monte Carlo
24
+ plotting figure saving and GIF helpers
25
+ demos ready-made figures, run with ``python -m qplay run <name>``
26
+ animations GIFs, run with ``python -m qplay animate <name>``
27
+ """
28
+
29
+ __version__ = "0.3.0"
@@ -0,0 +1,58 @@
1
+ """Command line.
2
+
3
+ qplay list show demos and animations
4
+ qplay run <name|all> [--out DIR] render demo figures (PNG)
5
+ qplay animate <name|all> [--frames N] [--fps F] [--out DIR] render animations (GIF)
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+
12
+ from . import __version__, animations, demos
13
+
14
+
15
+ def _summary(fn):
16
+ doc = (fn.__doc__ or "").strip().splitlines()
17
+ return doc[0] if doc else ""
18
+
19
+
20
+ def main(argv=None):
21
+ parser = argparse.ArgumentParser(prog="qplay", description="Physics and maths playground")
22
+ parser.add_argument("--version", action="version", version=__version__)
23
+ sub = parser.add_subparsers(dest="command", required=True)
24
+ sub.add_parser("list", help="list demos and animations")
25
+ run = sub.add_parser("run", help="render demos to PNG files")
26
+ run.add_argument("names", nargs="+", help="demo names, or 'all'")
27
+ run.add_argument("--out", default="figures", help="output directory (default: figures)")
28
+ anim = sub.add_parser("animate", help="render animations to GIF files")
29
+ anim.add_argument("names", nargs="+", help="animation names, or 'all'")
30
+ anim.add_argument("--out", default="figures", help="output directory (default: figures)")
31
+ anim.add_argument("--frames", type=int, default=120, help="number of frames (default: 120)")
32
+ anim.add_argument("--fps", type=int, default=24, help="frames per second (default: 24)")
33
+ args = parser.parse_args(argv)
34
+
35
+ if args.command == "list":
36
+ print("Demos (qplay run NAME):")
37
+ for name in sorted(demos.DEMOS):
38
+ print(f" {name:22s}{_summary(demos.DEMOS[name])}")
39
+ print("Animations (qplay animate NAME):")
40
+ for name in sorted(animations.ANIMATIONS):
41
+ print(f" {name:22s}{_summary(animations.ANIMATIONS[name])}")
42
+ return 0
43
+
44
+ registry = demos.DEMOS if args.command == "run" else animations.ANIMATIONS
45
+ names = sorted(registry) if args.names == ["all"] else args.names
46
+ for name in names:
47
+ try:
48
+ if args.command == "run":
49
+ print(demos.run(name, args.out))
50
+ else:
51
+ print(animations.render(name, args.out, n_frames=args.frames, fps=args.fps))
52
+ except KeyError as err:
53
+ parser.error(str(err.args[0]))
54
+ return 0
55
+
56
+
57
+ if __name__ == "__main__":
58
+ raise SystemExit(main())