Running on PyPy
The supported built-in simulation engine, release/dispatching policies, intralogistics modules, text/JSON/SQLite logging and trace recording have been exercised on PyPy 3.11 with seeded outputs matching CPython for the tested workloads.
You can use PyPy when it helps your workload — typically long, compute-heavy simulations and large multi-run studies — without changing any of your code.
Why 3.11?
PyPy's latest release implements the Python 3.11 language. simulatte therefore keeps its
source within the 3.11 language (requires-python = ">=3.11") so it runs on PyPy as well as on
CPython 3.11+. When PyPy ships a 3.12 release, this floor can rise.
Installation (with uv)
uv can download and manage a PyPy interpreter for you:
# 1. Install a PyPy 3.11 interpreter
uv python install pypy-3.11
# 2. Create a PyPy virtual environment
uv venv --python pypy-3.11 .venv-pypy
# 3. Install simulatte into it
uv pip install --python .venv-pypy simulatte
# 4. Run your simulation on PyPy
.venv-pypy/bin/python my_simulation.py
Your simulation scripts are unchanged — only the interpreter differs. The base install excludes NumPy,
Matplotlib, and Gymnasium. For plots, install simulatte[plot]; for the experimental Gymnasium wrapper,
install simulatte[rl] (or simulatte[all] for both).
Supported features on PyPy
| Capability | PyPy 3.11 |
|---|---|
| Simulation engine + all release/dispatching policies | ✅ fully supported |
| Intralogistics (AGV fleet, warehouse, graph/pathfinding) | ✅ fully supported |
| Text / JSON logging | ✅ supported |
Trace recording and reading (TraceRecorder, Trace) |
✅ supported |
SQLite logging (Environment(log_db_path=…)) |
✅ supported |
Plotting (collector plot_*, …) |
⚠️ works, but matplotlib/numpy run through PyPy's slower cpyext C-extension bridge |
simulatte.experimental (Gymnasium RL wrapper) |
⚠️ best-effort — depends on numpy/gymnasium via cpyext; the module is unstable regardless |
Notes:
- The pure-Python dependencies (
simpy,tqdm,tabulate) are first-class on PyPy. matplotlibandnumpyare only needed for plotting and the experimental RL module — they are never on the simulation hot path. Headless simulations that do not use the RL wrapper need neither extra. The PyPy CI lane runs the core and intralogistics suites without either extra; dependency-related skips are limited to NumPy-specific checks and the optional RL export check. Plotting and RL tests run on CPython with all extras installed.
Determinism across interpreters
Within one interpreter, runs are fully deterministic under a fixed Environment(seed=...). Across
CPython and PyPy, the standard-library random.Random streams are byte-identical, so seeded
simulations evolve the same way.
Simulatte sums floating-point values that feed events, dispatching priorities, due dates or KPIs with
math.fsum, which is exactly rounded on every interpreter. (The builtin sum() is compensated on
CPython 3.12+ and plain on CPython 3.11 and PyPy, so it can differ in the last bit under cancellation.) The
reference workloads therefore give the same semantic digest on CPython and PyPy. The guarantee covers the
library's own sums and the tested workloads: a custom model that sums signed terms of very different
magnitudes with sum() on the decision path can still diverge, and results that go through the platform's
libm (log, exp) may differ in the last bit between platforms. The run manifest records the interpreter,
so a digest mismatch can be explained. If you need cross-interpreter bit-reproducibility, validate your own
model.
Performance
PyPy's JIT can improve throughput on long, compute-heavy runs (it pays off after warmup, so short one-shot simulations may see little benefit or a small startup cost). The gain is workload-dependent — benchmark your own model. Keep CPython as your default for development, plotting, and the experimental RL module.
0.13 recording limitation on PyPy 8.0.0
On the stock PyPy 8.0.0 / Python 3.11.16 Linux x86-64 runtime used by CI, the production benchmark's semantic digest, KPI trace and full trace took 7.82×, 8.31× and 9.81×, respectively, the time of the same simulation with metrics and recording disabled in the 0.13 release check. These exceed Simulatte's accepted PyPy targets of 4.3×, 4.5× and 7.0×. The recording measurements are report-only, so passing CI does not imply that these targets are met.
The tested runs retain matching trajectories and semantic digests. A same-machine comparison with an older PyPy release and isolated hashing measurements identify runtime-dependent BLAKE2 overhead as part of the slowdown; the remaining cost is still under investigation. CPython meets the recording targets in the release-check benchmark. If recording cost matters, compare CPython and PyPy on your own model and exact interpreter version.
This is a documented performance limitation of 0.13.0, tracked in issue #59. The existing targets remain unchanged.