Leviathan Engine
High-performance C++ simulation core for large swarms. Leviathan advances agent states using physics and environment models, accepts actions from Gossamer, and logs outputs for Maneuver.Map to orchestrate, visualize, and analyze experiments.
At a glance
- Integrators: semi-implicit Euler (default), RK4, velocity-Verlet.
- Communication: bandwidth-limited, loss-prone, delay-buffered channel.
- Collisions: sphere-sphere elastic resolution with configurable restitution.
- Scale: demonstrated at 10⁶ agents on a single CPU node; OpenMP parallel.
- Reproducibility: checkpoints carry serialized RNG state.
Minimal Python example
from leviathan import Simulation
sim = Simulation({
"dt": "0.1",
"num_agents": "1000",
"integrator": "velocity_verlet",
"collision_radius": "0.5",
"comm_range": "10.0",
"comm_bw_kbps": "8.0",
"seed": "42",
})
# Advance 100 steps with zero action (agents drift under their initial vels)
for _ in range(100):
sim.step()
print(sim.metrics())For MARL rollouts against PettingZoo, use leviathan_marl.env.LeviathanParallelEnv; it skips HTTP and runs the physics in-process. The MARL package is named leviathan_marl so it doesn’t shadow the pybind11 leviathan extension on sys.path.
Cite this tool
@software{arboria2026leviathan,
title = {Leviathan Engine: high-performance multi-agent physics simulation},
author = {{Arboria Labs}},
year = {2026},
url = {https://www.arborialabs.com/tools/leviathan_engine}
}How It Fits With Gossamer + Maneuver.Map
- Leviathan: physics, environment, agent state, scalable stepping, logging.
- Gossamer: provides action policies (e.g., flocking) and metrics; used via Python bindings.
- Maneuver.Map: controls runs, tunes parameters, stores data (e.g., GCS), and serves 3D visualization and APIs.
Features
- Selectable integrator — Euler (default), RK4, or velocity-Verlet (symplectic; correct default for orbital / long-horizon scenarios where Euler drifts >20% over 10⁵ steps).
- Real C++ communication channel — bandwidth (
comm_bw_kbps), per-link capacity, Bernoulli loss (comm_loss_prob), propagation delay (comm_latency_stepsor derived fromcomm_latency_ms). No-op when none are set; zero performance regression for legacy callers. Aggregate counters (comm_attempted / delivered / dropped_loss / dropped_range / bytes_in_flight) surfaced inmetrics(). - Sphere-sphere collisions —
collision_radius+collision_restitution(0 = stick-and-share, 1 = elastic).collisions_last_stepreported inmetrics(). - OpenMP parallelism — over physics, environment-field, and collision loops (
LEVIATHAN_WITH_OPENMP=ONby default; falls back to serial cleanly when OpenMP is unavailable). - Deterministic checkpoints —
Simulation::get_rng_state()/set_rng_state()serialize thestd::mt19937state so resumed runs are byte-identical to non-resumed runs. Exposed through pybind and the HTTP/checkpoint//restoreendpoints. - Environment fields —
none,uniformvector, orcentralinverse-square (gravity-like). - Spatial hashing + neighbor-only physics — neighbor queries within a cutoff radius rather than all-to-all dynamics. Demonstrated at 10⁶ agents on a single CPU node.
- PettingZoo
ParallelEnvwrapper —leviathan_marl.env.LeviathanParallelEnvfor drop-in MARL training (RLlib, CleanRL, MARLlib, TorchRL). Sits on top of the in-process pybind module so no HTTP round-trip per step. - Differentiable JAX backend stub —
leviathan_diff_braxports Euler and velocity-Verlet to pure JAX for gradient-based swarm-shaping research. - Python bindings — pybind11 module named
leviathanwith aSimulationclass.
Build & Run (Local)
mkdir -p build && cd build
cmake -Dpybind11_DIR="$(python3 -m pybind11 --cmakedir)" ..
make -j"$(nproc)"
python3 -c "import leviathan; from leviathan import Simulation; print('OK')"Force-disable OpenMP (debugging or unsupported toolchains):
cmake -DLEVIATHAN_WITH_OPENMP=OFF -Dpybind11_DIR="$(python3 -m pybind11 --cmakedir)" ..Output Schema
- CSV columns:
timestamp, agent_id, position_x, position_y, position_z. The Maneuver.Map runner extends this with optional per-algorithm columns (role,soc,aoi,density,pheromone) when relevant. - Parquet part files at
<output_path>.parts/part-<step>.parquet— one per logged step. Maneuver.Map’s/framesAPI streams these viapyarrow.datasetwith predicate pushdown ontimestampand column pruning. - CSV → Parquet conversion utility:
python scripts/csv_to_parquet.py path/to/leviathan_output.csv.
Python Integration
- Bindings module name:
leviathan. The pybind11 extension exports aSimulationclass withstep(),metrics(),get_rng_state(),set_rng_state(),checkpoint(), andrestore(). - MARL wrapper:
leviathan_marl.env.LeviathanParallelEnv(separate package name to avoid shadowing the extension onsys.path). - Differentiable backend:
leviathan_diff_braxports the kernel to JAX for gradient-based research; parity at 1k agents today, larger scales on the roadmap. - Used by Maneuver.Map’s runner via either HTTP (
ENGINE_MODE=http) or in-process pybind (ENGINE_MODE=inprocess); the latter skips a full HTTP round-trip per step and is what we use for million-step rollouts.
Docker
- See
Dockerfilefor a Cloud‑ready build of core + bindings. The Maneuver.Map Orchestrator image builds Leviathan and serves APIs.
Typical Research Workflow
- Define agent logic in Gossamer (policies, metrics).
- Configure Leviathan (environment, agents, output format and frequency).
- Run simulation locally or via orchestrator; log CSV/Parquet.
- Visualize and analyze in Maneuver.Map.
Configuration Reference
Leviathan reads a flat string-valued config map (HTTP body, pybind kwarg dict, or key: value file). Every key is optional; defaults are noted.
Core physics
dt(float, default1.0) — simulation time step in seconds.num_agents(int, default10).bound(float, default100.0) — periodic-box half-extent.integrator(string, default"euler") —"euler" | "rk4" | "velocity_verlet".acc_min,acc_max(float) — random-action bounds for the legacy demo path; the Maneuver.Map runner always supplies actions from Gossamer and these are ignored.seed(int) — deterministic agent-state initialization.
Environment field
field_type(string) —"none"|"uniform"|"central"(inverse-square, gravity-like toward origin).field_vx,field_vy,field_vz(float) — components for"uniform"fields.field_strength(float) — scalar strength for"central"or"uniform"fields.
Communication channel (no-op when all default)
comm_range(float, metres).comm_bw_kbps(float) — shared per-link bandwidth cap.comm_bundle_kb(float, default0.1) — bundle size in KB.comm_loss_prob(float, 0–1) — Bernoulli per-bundle drop probability.comm_latency_stepsorcomm_latency_ms— fixed propagation delay; the latter is converted usingdt.comm_seed(int) — independent RNG for the comms layer.
Collisions (no-op when collision_radius == 0)
collision_radius(float, metres).collision_restitution(float, 0–1) — 0 = stick-and-share, 1 = elastic.
Output (when invoked through the legacy CLI runner; the Maneuver.Map runner has its own writer)
output_path— CSV path; Parquet parts go tooutput_path + ".parts".output_frequency(int) — write rows every N steps.output_format—"csv"(default) or"parquet"(requires Arrow/Parquet at build).
Output Details
- CSV schema (engine default):
timestamp,agent_id,position_x,position_y,position_z. - Parquet schema (if enabled): same columns as CSV; emitted in parts under
<output_path>.parts/. - Maneuver.Map may extend the schema when orchestrating (CSV includes additional columns like
role,soc,aoi,density,pheromoneand emits Parquet parts by default). The viewer selects and streams only the columns it needs.
Performance Notes
- Use higher
output_frequencyto reduce I/O when stepping many agents. - Prefer Parquet for downstream slicing/streaming in Maneuver.Map; predicate pushdown prunes time ranges and columns server‑side.
- For very large
num_agents, ensure the surrounding container has sufficient memory; simulation cost scales roughly linearly with agent count per step.