simulsi 0.2.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.
- simulsi-0.2.0/.gitignore +30 -0
- simulsi-0.2.0/CHANGELOG.md +78 -0
- simulsi-0.2.0/LICENSE +21 -0
- simulsi-0.2.0/NOTICE +11 -0
- simulsi-0.2.0/PKG-INFO +206 -0
- simulsi-0.2.0/README.md +151 -0
- simulsi-0.2.0/benchmarks/README.md +59 -0
- simulsi-0.2.0/docs/architecture.md +163 -0
- simulsi-0.2.0/docs/cli.md +115 -0
- simulsi-0.2.0/docs/concepts.md +339 -0
- simulsi-0.2.0/docs/examples.md +93 -0
- simulsi-0.2.0/docs/experiments.md +266 -0
- simulsi-0.2.0/docs/extending.md +144 -0
- simulsi-0.2.0/docs/faq.md +100 -0
- simulsi-0.2.0/docs/getting-started.md +135 -0
- simulsi-0.2.0/docs/index.md +35 -0
- simulsi-0.2.0/docs/research.md +93 -0
- simulsi-0.2.0/docs/visualization.md +112 -0
- simulsi-0.2.0/pyproject.toml +130 -0
- simulsi-0.2.0/src/simulsi/__init__.py +70 -0
- simulsi-0.2.0/src/simulsi/__main__.py +5 -0
- simulsi-0.2.0/src/simulsi/_version.py +1 -0
- simulsi-0.2.0/src/simulsi/analysis/__init__.py +24 -0
- simulsi-0.2.0/src/simulsi/analysis/comparison.py +154 -0
- simulsi-0.2.0/src/simulsi/analysis/report.py +46 -0
- simulsi-0.2.0/src/simulsi/analysis/sensitivity.py +387 -0
- simulsi-0.2.0/src/simulsi/benchmarks.py +128 -0
- simulsi-0.2.0/src/simulsi/cli/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/cli/main.py +486 -0
- simulsi-0.2.0/src/simulsi/cli/templates.py +96 -0
- simulsi-0.2.0/src/simulsi/config/__init__.py +19 -0
- simulsi-0.2.0/src/simulsi/config/schema.py +263 -0
- simulsi-0.2.0/src/simulsi/core/__init__.py +13 -0
- simulsi-0.2.0/src/simulsi/core/checkpoint.py +159 -0
- simulsi-0.2.0/src/simulsi/core/clock.py +87 -0
- simulsi-0.2.0/src/simulsi/core/model.py +441 -0
- simulsi-0.2.0/src/simulsi/core/simulation.py +670 -0
- simulsi-0.2.0/src/simulsi/core/trace.py +79 -0
- simulsi-0.2.0/src/simulsi/cost/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/cost/model.py +193 -0
- simulsi-0.2.0/src/simulsi/entities/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/entities/entity.py +120 -0
- simulsi-0.2.0/src/simulsi/errors.py +50 -0
- simulsi-0.2.0/src/simulsi/events/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/events/event.py +221 -0
- simulsi-0.2.0/src/simulsi/experiments/__init__.py +17 -0
- simulsi-0.2.0/src/simulsi/experiments/experiment.py +548 -0
- simulsi-0.2.0/src/simulsi/experiments/montecarlo.py +261 -0
- simulsi-0.2.0/src/simulsi/experiments/provenance.py +61 -0
- simulsi-0.2.0/src/simulsi/introspection/__init__.py +21 -0
- simulsi-0.2.0/src/simulsi/introspection/graph.py +210 -0
- simulsi-0.2.0/src/simulsi/metrics/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/metrics/collectors.py +348 -0
- simulsi-0.2.0/src/simulsi/models/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/models/queueing.py +73 -0
- simulsi-0.2.0/src/simulsi/optimization/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/optimization/objective.py +131 -0
- simulsi-0.2.0/src/simulsi/processes/__init__.py +31 -0
- simulsi-0.2.0/src/simulsi/processes/disruption.py +165 -0
- simulsi-0.2.0/src/simulsi/processes/process.py +346 -0
- simulsi-0.2.0/src/simulsi/py.typed +0 -0
- simulsi-0.2.0/src/simulsi/queues/__init__.py +4 -0
- simulsi-0.2.0/src/simulsi/queues/discipline.py +99 -0
- simulsi-0.2.0/src/simulsi/queues/queue.py +256 -0
- simulsi-0.2.0/src/simulsi/randomness/__init__.py +47 -0
- simulsi-0.2.0/src/simulsi/randomness/distributions.py +449 -0
- simulsi-0.2.0/src/simulsi/randomness/stream.py +117 -0
- simulsi-0.2.0/src/simulsi/resources/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/resources/resource.py +519 -0
- simulsi-0.2.0/src/simulsi/scenarios/__init__.py +10 -0
- simulsi-0.2.0/src/simulsi/scenarios/scenario.py +132 -0
- simulsi-0.2.0/src/simulsi/serialization/__init__.py +23 -0
- simulsi-0.2.0/src/simulsi/serialization/io.py +128 -0
- simulsi-0.2.0/src/simulsi/statistics/__init__.py +37 -0
- simulsi-0.2.0/src/simulsi/statistics/core.py +418 -0
- simulsi-0.2.0/src/simulsi/validation/__init__.py +3 -0
- simulsi-0.2.0/src/simulsi/validation/validate.py +168 -0
- simulsi-0.2.0/src/simulsi/visualization/__init__.py +27 -0
- simulsi-0.2.0/src/simulsi/visualization/plots.py +423 -0
- simulsi-0.2.0/src/simulsi/web/__init__.py +1 -0
- simulsi-0.2.0/src/simulsi/web/server.py +338 -0
- simulsi-0.2.0/src/simulsi/web/static/assets/index-CNMcVqxw.css +2 -0
- simulsi-0.2.0/src/simulsi/web/static/assets/index-DDtrYZla.js +9 -0
- simulsi-0.2.0/src/simulsi/web/static/index.html +13 -0
- simulsi-0.2.0/tests/cli/test_cli.py +244 -0
- simulsi-0.2.0/tests/docs/test_docs.py +62 -0
- simulsi-0.2.0/tests/integration/test_analysis_features.py +366 -0
- simulsi-0.2.0/tests/integration/test_examples.py +52 -0
- simulsi-0.2.0/tests/integration/test_experiments.py +221 -0
- simulsi-0.2.0/tests/integration/test_visualization.py +71 -0
- simulsi-0.2.0/tests/integration/test_web_server.py +151 -0
- simulsi-0.2.0/tests/performance/test_performance.py +33 -0
- simulsi-0.2.0/tests/property/test_invariants.py +181 -0
- simulsi-0.2.0/tests/statistical/test_queueing_theory.py +66 -0
- simulsi-0.2.0/tests/unit/test_checkpoint.py +90 -0
- simulsi-0.2.0/tests/unit/test_entities.py +71 -0
- simulsi-0.2.0/tests/unit/test_events.py +173 -0
- simulsi-0.2.0/tests/unit/test_metrics.py +79 -0
- simulsi-0.2.0/tests/unit/test_model.py +122 -0
- simulsi-0.2.0/tests/unit/test_montecarlo_and_engine_extras.py +122 -0
- simulsi-0.2.0/tests/unit/test_processes.py +181 -0
- simulsi-0.2.0/tests/unit/test_queues.py +103 -0
- simulsi-0.2.0/tests/unit/test_randomness.py +169 -0
- simulsi-0.2.0/tests/unit/test_resources.py +316 -0
- simulsi-0.2.0/tests/unit/test_statistics.py +123 -0
- simulsi-0.2.0/web/README.md +41 -0
simulsi-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.mypy_cache/
|
|
12
|
+
.ruff_cache/
|
|
13
|
+
.hypothesis/
|
|
14
|
+
.coverage
|
|
15
|
+
coverage.xml
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# SimulSI outputs are per-user
|
|
19
|
+
simulsi-results/
|
|
20
|
+
*.checkpoint.jsonl
|
|
21
|
+
|
|
22
|
+
# Node / web
|
|
23
|
+
node_modules/
|
|
24
|
+
web/frontend/dist/
|
|
25
|
+
src/simulsi/web/static/
|
|
26
|
+
|
|
27
|
+
# OS / editors
|
|
28
|
+
.DS_Store
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-10-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Preemptive resources (`preemptive=True` with the priority discipline);
|
|
14
|
+
evicted processes receive `Interrupt(Preempted(...))`.
|
|
15
|
+
- Sobol first-order and total-effect sensitivity indices
|
|
16
|
+
(`simulsi.analysis.sobol_indices`) with bootstrap CIs, validated against
|
|
17
|
+
the Ishigami function.
|
|
18
|
+
- Checkpoints of running simulations (`sim.save_checkpoint`,
|
|
19
|
+
`Simulation.load_checkpoint`) restored by verified deterministic replay.
|
|
20
|
+
- PyPI publishing workflow (trusted publishing).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Hold times in event-log records were wrong for units granted at t = 0.
|
|
25
|
+
|
|
26
|
+
## [0.1.0] - 2026-10-02
|
|
27
|
+
|
|
28
|
+
First public release.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Discrete-event engine: float clock with `timedelta`/`datetime` conversion,
|
|
33
|
+
heap-based event queue with deterministic `(time, priority, sequence)`
|
|
34
|
+
ordering, scheduling, rescheduling, cancellation, `run(until=...)`
|
|
35
|
+
that stops exactly at the horizon, snapshots and a structured event log
|
|
36
|
+
(JSON/CSV/Parquet export).
|
|
37
|
+
- Generator-based processes with timeouts, signals, `all_of`/`any_of`,
|
|
38
|
+
waiting on other processes, interrupts and error propagation.
|
|
39
|
+
- Resources with FIFO/LIFO/priority/custom disciplines, reneging,
|
|
40
|
+
capacity changes, downtime, automatic statistics; blocking queues.
|
|
41
|
+
- Entities with attributes, state history and time-in-system metrics.
|
|
42
|
+
- Seeded random streams (PCG64, named sub-streams via `SeedSequence`) and 12
|
|
43
|
+
distributions with validation and configuration specs.
|
|
44
|
+
- Metrics: tallies, time-weighted gauges, counters, histograms, warm-up reset.
|
|
45
|
+
- Models (`Model`, `@model`, `Parameter`), scenarios, full-factorial grids.
|
|
46
|
+
- Experiments with common random numbers, provenance (git commit,
|
|
47
|
+
environment), parallel workers, checkpoint/resume and JSON/CSV/Parquet
|
|
48
|
+
export.
|
|
49
|
+
- Monte Carlo (random and Latin hypercube sampling, vectorised models,
|
|
50
|
+
simulation models), statistics (t/bootstrap/Wilson intervals, replication
|
|
51
|
+
advice, convergence, batch means, paired and Welch differences), scenario
|
|
52
|
+
comparison, sensitivity analysis (OAT, finite differences, Pearson,
|
|
53
|
+
Spearman, SRC).
|
|
54
|
+
- Failure/recovery processes, scheduled disruptions, cost models and an
|
|
55
|
+
optimisation `Objective` adapter.
|
|
56
|
+
- Model validation (smoke run with deadlock / unreleased-resource / state
|
|
57
|
+
checks) and flow/state graph introspection (Mermaid, DOT).
|
|
58
|
+
- Optional matplotlib/Plotly visualisation.
|
|
59
|
+
- YAML experiment configuration (strict schema, safe loading, path checks)
|
|
60
|
+
and the `simulsi` CLI: `init`, `validate`, `run`, `experiment`, `analyze`,
|
|
61
|
+
`benchmark`, `visualize`, `ui`.
|
|
62
|
+
- Optional React + TypeScript dashboard (`simulsi ui`): load experiments,
|
|
63
|
+
view parameters and provenance, run models, compare scenarios, inspect
|
|
64
|
+
distributions and convergence, trace single runs (timeline, queues,
|
|
65
|
+
utilization) and export JSON/CSV. Served locally on 127.0.0.1.
|
|
66
|
+
- Six domain examples: bank, hospital, warehouse, manufacturing,
|
|
67
|
+
transportation, aviation - plus a minimal M/M/c example.
|
|
68
|
+
- Benchmark suite (`benchmarks/run_benchmarks.py`, `simulsi benchmark`) with
|
|
69
|
+
measured results, and performance regression tests.
|
|
70
|
+
- Documentation: user guide, architecture, research workflow, extension guide,
|
|
71
|
+
FAQ; documentation code blocks are executed by the test suite.
|
|
72
|
+
|
|
73
|
+
### Known limitations
|
|
74
|
+
|
|
75
|
+
- No preemptive resources, continuous-time dynamics or single-run
|
|
76
|
+
checkpoint/restore (experiments are checkpointed per replication).
|
|
77
|
+
- Sensitivity analysis is local / correlation-based; no Sobol indices yet.
|
|
78
|
+
- Not yet published on PyPI; install from source.
|
simulsi-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yash Jindal
|
|
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.
|
simulsi-0.2.0/NOTICE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
NOTICE
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
This project is licensed under the MIT License (see LICENSE).
|
|
5
|
+
|
|
6
|
+
You are free to use, study, modify and build on this code, including
|
|
7
|
+
commercially. The MIT License requires that you keep the copyright notice
|
|
8
|
+
and license text with any substantial portion you reuse.
|
|
9
|
+
|
|
10
|
+
Nothing in this NOTICE modifies, restricts or adds conditions to the MIT
|
|
11
|
+
License. If the two ever appear to conflict, the LICENSE file governs.
|
simulsi-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: simulsi
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A general-purpose, reproducible simulation and scenario experimentation framework for Python.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Yashjindal11/simulsi
|
|
6
|
+
Project-URL: Documentation, https://github.com/Yashjindal11/simulsi/tree/main/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/Yashjindal11/simulsi/issues
|
|
8
|
+
Author: Yash Jindal
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: discrete-event-simulation,experiments,monte-carlo,operations-research,queueing,sensitivity-analysis,simulation
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: numpy>=1.26
|
|
25
|
+
Requires-Dist: pydantic>=2.6
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Requires-Dist: scipy>=1.11
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: matplotlib>=3.8; extra == 'all'
|
|
30
|
+
Requires-Dist: pandas>=2.1; extra == 'all'
|
|
31
|
+
Requires-Dist: plotly>=5.18; extra == 'all'
|
|
32
|
+
Requires-Dist: pyarrow>=14; extra == 'all'
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
35
|
+
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
36
|
+
Requires-Dist: matplotlib>=3.8; extra == 'dev'
|
|
37
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
38
|
+
Requires-Dist: pandas>=2.1; extra == 'dev'
|
|
39
|
+
Requires-Dist: plotly>=5.18; extra == 'dev'
|
|
40
|
+
Requires-Dist: pyarrow>=14; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: ruff==0.16.10; extra == 'dev'
|
|
44
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
45
|
+
Provides-Extra: pandas
|
|
46
|
+
Requires-Dist: pandas>=2.1; extra == 'pandas'
|
|
47
|
+
Provides-Extra: parquet
|
|
48
|
+
Requires-Dist: pandas>=2.1; extra == 'parquet'
|
|
49
|
+
Requires-Dist: pyarrow>=14; extra == 'parquet'
|
|
50
|
+
Provides-Extra: plotly
|
|
51
|
+
Requires-Dist: plotly>=5.18; extra == 'plotly'
|
|
52
|
+
Provides-Extra: viz
|
|
53
|
+
Requires-Dist: matplotlib>=3.8; extra == 'viz'
|
|
54
|
+
Description-Content-Type: text/markdown
|
|
55
|
+
|
|
56
|
+
# SimulSI
|
|
57
|
+
|
|
58
|
+
**Simulation Intelligence** - *Model the system. Simulate the future.*
|
|
59
|
+
|
|
60
|
+
SimulSI is a general-purpose, reproducible simulation and scenario
|
|
61
|
+
experimentation framework for Python. You describe a system - customers and
|
|
62
|
+
tellers, patients and doctors, jobs and machines, aircraft and gates, requests
|
|
63
|
+
and servers - as discrete-event processes; SimulSI runs it, measures it, and
|
|
64
|
+
helps you answer *what if?* with replications, confidence intervals, scenario
|
|
65
|
+
comparisons, Monte Carlo and sensitivity analysis.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from simulsi import Experiment, Scenario, Simulation, model
|
|
69
|
+
from simulsi.randomness import Exponential
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@model(duration=480, parameters={"arrival_rate": 1.0, "tellers": 3})
|
|
73
|
+
def bank(sim: Simulation, p):
|
|
74
|
+
tellers = sim.resource("teller", capacity=p.tellers)
|
|
75
|
+
arrivals, service = sim.stream("arrivals"), sim.stream("service")
|
|
76
|
+
|
|
77
|
+
def customer(sim):
|
|
78
|
+
yield sim.request(tellers) # wait for a teller
|
|
79
|
+
yield Exponential(mean=2.6).sample(service) # being served
|
|
80
|
+
sim.release(tellers)
|
|
81
|
+
|
|
82
|
+
def source(sim):
|
|
83
|
+
while True:
|
|
84
|
+
yield Exponential(rate=p.arrival_rate).sample(arrivals)
|
|
85
|
+
sim.process(customer(sim))
|
|
86
|
+
|
|
87
|
+
sim.process(source(sim))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
result = Experiment(
|
|
91
|
+
bank,
|
|
92
|
+
[Scenario("baseline"), Scenario("four_tellers", {"tellers": 4})],
|
|
93
|
+
replications=30,
|
|
94
|
+
seed=42,
|
|
95
|
+
).run()
|
|
96
|
+
print(result.format_summary(["resource.teller.wait.mean", "resource.teller.utilization"]))
|
|
97
|
+
print(result.compare("baseline", metrics=["resource.teller.wait.mean"]).format())
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Why SimulSI?
|
|
101
|
+
|
|
102
|
+
Discrete-event engines tell you what happened in *one* run. Decisions need
|
|
103
|
+
more: how sure are we, which scenario is better, which input matters most, and
|
|
104
|
+
can someone else reproduce this? SimulSI is built **experiment-first**:
|
|
105
|
+
|
|
106
|
+
| | |
|
|
107
|
+
|---|---|
|
|
108
|
+
| **Reproducible by construction** | Every run is determined by its seed. Named random streams (`sim.stream("arrivals")`) are derived from the seed with NumPy's `SeedSequence`, so adding a resource never shifts another stream. Serial and parallel runs give identical numbers. |
|
|
109
|
+
| **Scenario comparison** | Scenarios share replication seeds (*common random numbers*) and comparisons use paired confidence intervals, which are usually much tighter than comparing independent runs. |
|
|
110
|
+
| **Statistics built in** | t and bootstrap CIs, Wilson intervals for probabilities, "have I run enough replications?" advice, convergence curves, batch means for long runs. |
|
|
111
|
+
| **Monte Carlo & sensitivity** | Propagate input uncertainty (random or Latin hypercube sampling, vectorised or per simulation run). One-at-a-time, finite-difference, correlation and standardised-regression sensitivity. |
|
|
112
|
+
| **Provenance** | Each experiment records id, model name/version, git commit, timestamp, seeds, parameters, runtime and environment. Results export to JSON, CSV and Parquet. |
|
|
113
|
+
| **Model introspection** | `snapshot()` of live state, structured event logs, observed flow graphs (arrival -> queue -> service -> departure), entity state machines, and model validation with a smoke run (unreleased resources, possible deadlocks, zero capacities, unreached states). |
|
|
114
|
+
| **Decision support** | Cost/revenue models on top of metrics; an `Objective` adapter that hands models to scipy.optimize, OR-Tools, evolutionary or Bayesian optimisers without depending on any of them. |
|
|
115
|
+
| **Local-first** | No LLMs, API keys, telemetry or network access. Core dependencies: NumPy, SciPy, pydantic, PyYAML. Plotting, pandas, Parquet and the web dashboard are optional. |
|
|
116
|
+
|
|
117
|
+
SimulSI is not a replacement for mature engines such as SimPy or Salabim, or
|
|
118
|
+
for commercial packages; see
|
|
119
|
+
[how SimulSI differs](docs/faq.md#how-does-simulsi-compare-with-other-tools).
|
|
120
|
+
|
|
121
|
+
## Installation
|
|
122
|
+
|
|
123
|
+
SimulSI is not on PyPI yet; install from source (Python 3.11+):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git clone https://github.com/Yashjindal11/simulsi.git && cd simulsi
|
|
127
|
+
python -m venv .venv
|
|
128
|
+
.venv/bin/pip install -e . # core
|
|
129
|
+
.venv/bin/pip install -e ".[viz]" # + matplotlib plots
|
|
130
|
+
.venv/bin/pip install -e ".[all]" # + pandas, Parquet, matplotlib, Plotly
|
|
131
|
+
.venv/bin/pip install -e ".[dev]" # everything needed to run the tests
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Command line
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
simulsi init my-study # starter model.py + experiment.yaml
|
|
138
|
+
simulsi validate my-study/experiment.yaml # schema check + model smoke run
|
|
139
|
+
simulsi run examples/queue.py -p servers=3 # one replication, metrics table
|
|
140
|
+
simulsi experiment my-study/experiment.yaml # scenarios x replications, comparison, saved results
|
|
141
|
+
simulsi analyze my-study/results/service-desk --precision 0.05
|
|
142
|
+
simulsi visualize my-study/results/service-desk --out plots
|
|
143
|
+
simulsi benchmark # events/sec on this machine
|
|
144
|
+
simulsi ui my-study/results/service-desk # local dashboard on 127.0.0.1
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Experiments are described in YAML - data only, validated against a strict
|
|
148
|
+
schema:
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
model: model.py:service_desk
|
|
152
|
+
simulation: {seed: 42, duration: 480}
|
|
153
|
+
experiment: {replications: 30, workers: 4}
|
|
154
|
+
parameters: {arrival_rate: 0.9}
|
|
155
|
+
scenarios:
|
|
156
|
+
- {name: high_demand, parameters: {arrival_rate: 1.3}}
|
|
157
|
+
- {name: extra_server, parameters: {servers: 3}}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Examples
|
|
161
|
+
|
|
162
|
+
| Example | Shows |
|
|
163
|
+
|---|---|
|
|
164
|
+
| [`queue.py`](examples/queue.py) | Minimal M/M/c model checked against Erlang C |
|
|
165
|
+
| [`bank_queue.py`](examples/bank_queue.py) | Reneging customers, staffing scenarios, replication advice |
|
|
166
|
+
| [`hospital.py`](examples/hospital.py) | Priority triage, several resources, service levels |
|
|
167
|
+
| [`warehouse.py`](examples/warehouse.py) | Time-varying demand, picking/packing buffers, backlog |
|
|
168
|
+
| [`manufacturing.py`](examples/manufacturing.py) | Breakdowns with a repair crew, blocking, cost model |
|
|
169
|
+
| [`transportation.py`](examples/transportation.py) | Shuttle loop, boarding capacity, left-behind passengers |
|
|
170
|
+
| [`aviation.py`](examples/aviation.py) | Synthetic airport gates, taxiway holds, tows, weather disruption |
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
python examples/hospital.py
|
|
174
|
+
python scripts/run_examples.py # all of them, quick mode
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Documentation
|
|
178
|
+
|
|
179
|
+
- [Getting started](docs/getting-started.md) - installation, quickstart, first experiment
|
|
180
|
+
- [Core concepts](docs/concepts.md) - simulation, events, entities, resources, queues, processes, randomness, metrics, disruptions, validation, introspection
|
|
181
|
+
- [Experiments and analysis](docs/experiments.md) - scenarios, experiments, Monte Carlo, statistics, comparison, sensitivity, cost, optimisation
|
|
182
|
+
- [Visualization](docs/visualization.md) - plots and the web dashboard
|
|
183
|
+
- [CLI and configuration](docs/cli.md)
|
|
184
|
+
- [Architecture](docs/architecture.md) - design, module map, performance, limitations
|
|
185
|
+
- [Extending SimulSI](docs/extending.md)
|
|
186
|
+
- [Research workflow](docs/research.md) - reproducibility, provenance, statistical practice
|
|
187
|
+
- [Examples](docs/examples.md) - walkthroughs of the domain examples
|
|
188
|
+
- [FAQ](docs/faq.md) - including how SimulSI compares with other tools
|
|
189
|
+
- [Benchmarks](benchmarks/README.md) - measured numbers and how to reproduce them
|
|
190
|
+
|
|
191
|
+
## Status
|
|
192
|
+
|
|
193
|
+
SimulSI is alpha software (0.x) and the API may still change. It is tested on
|
|
194
|
+
Python 3.11-3.13 (Linux, macOS, Windows in CI) with unit, property-based
|
|
195
|
+
(Hypothesis), statistical, integration, CLI and performance tests - including
|
|
196
|
+
checks of simulated M/M/c queues against closed-form Erlang-C results.
|
|
197
|
+
|
|
198
|
+
## Contributing
|
|
199
|
+
|
|
200
|
+
Issues and pull requests are welcome - see [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
201
|
+
and the [Code of Conduct](CODE_OF_CONDUCT.md). For security reports see
|
|
202
|
+
[SECURITY.md](SECURITY.md).
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
[MIT](LICENSE) © 2026 Yash Jindal
|
simulsi-0.2.0/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# SimulSI
|
|
2
|
+
|
|
3
|
+
**Simulation Intelligence** - *Model the system. Simulate the future.*
|
|
4
|
+
|
|
5
|
+
SimulSI is a general-purpose, reproducible simulation and scenario
|
|
6
|
+
experimentation framework for Python. You describe a system - customers and
|
|
7
|
+
tellers, patients and doctors, jobs and machines, aircraft and gates, requests
|
|
8
|
+
and servers - as discrete-event processes; SimulSI runs it, measures it, and
|
|
9
|
+
helps you answer *what if?* with replications, confidence intervals, scenario
|
|
10
|
+
comparisons, Monte Carlo and sensitivity analysis.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from simulsi import Experiment, Scenario, Simulation, model
|
|
14
|
+
from simulsi.randomness import Exponential
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@model(duration=480, parameters={"arrival_rate": 1.0, "tellers": 3})
|
|
18
|
+
def bank(sim: Simulation, p):
|
|
19
|
+
tellers = sim.resource("teller", capacity=p.tellers)
|
|
20
|
+
arrivals, service = sim.stream("arrivals"), sim.stream("service")
|
|
21
|
+
|
|
22
|
+
def customer(sim):
|
|
23
|
+
yield sim.request(tellers) # wait for a teller
|
|
24
|
+
yield Exponential(mean=2.6).sample(service) # being served
|
|
25
|
+
sim.release(tellers)
|
|
26
|
+
|
|
27
|
+
def source(sim):
|
|
28
|
+
while True:
|
|
29
|
+
yield Exponential(rate=p.arrival_rate).sample(arrivals)
|
|
30
|
+
sim.process(customer(sim))
|
|
31
|
+
|
|
32
|
+
sim.process(source(sim))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
result = Experiment(
|
|
36
|
+
bank,
|
|
37
|
+
[Scenario("baseline"), Scenario("four_tellers", {"tellers": 4})],
|
|
38
|
+
replications=30,
|
|
39
|
+
seed=42,
|
|
40
|
+
).run()
|
|
41
|
+
print(result.format_summary(["resource.teller.wait.mean", "resource.teller.utilization"]))
|
|
42
|
+
print(result.compare("baseline", metrics=["resource.teller.wait.mean"]).format())
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Why SimulSI?
|
|
46
|
+
|
|
47
|
+
Discrete-event engines tell you what happened in *one* run. Decisions need
|
|
48
|
+
more: how sure are we, which scenario is better, which input matters most, and
|
|
49
|
+
can someone else reproduce this? SimulSI is built **experiment-first**:
|
|
50
|
+
|
|
51
|
+
| | |
|
|
52
|
+
|---|---|
|
|
53
|
+
| **Reproducible by construction** | Every run is determined by its seed. Named random streams (`sim.stream("arrivals")`) are derived from the seed with NumPy's `SeedSequence`, so adding a resource never shifts another stream. Serial and parallel runs give identical numbers. |
|
|
54
|
+
| **Scenario comparison** | Scenarios share replication seeds (*common random numbers*) and comparisons use paired confidence intervals, which are usually much tighter than comparing independent runs. |
|
|
55
|
+
| **Statistics built in** | t and bootstrap CIs, Wilson intervals for probabilities, "have I run enough replications?" advice, convergence curves, batch means for long runs. |
|
|
56
|
+
| **Monte Carlo & sensitivity** | Propagate input uncertainty (random or Latin hypercube sampling, vectorised or per simulation run). One-at-a-time, finite-difference, correlation and standardised-regression sensitivity. |
|
|
57
|
+
| **Provenance** | Each experiment records id, model name/version, git commit, timestamp, seeds, parameters, runtime and environment. Results export to JSON, CSV and Parquet. |
|
|
58
|
+
| **Model introspection** | `snapshot()` of live state, structured event logs, observed flow graphs (arrival -> queue -> service -> departure), entity state machines, and model validation with a smoke run (unreleased resources, possible deadlocks, zero capacities, unreached states). |
|
|
59
|
+
| **Decision support** | Cost/revenue models on top of metrics; an `Objective` adapter that hands models to scipy.optimize, OR-Tools, evolutionary or Bayesian optimisers without depending on any of them. |
|
|
60
|
+
| **Local-first** | No LLMs, API keys, telemetry or network access. Core dependencies: NumPy, SciPy, pydantic, PyYAML. Plotting, pandas, Parquet and the web dashboard are optional. |
|
|
61
|
+
|
|
62
|
+
SimulSI is not a replacement for mature engines such as SimPy or Salabim, or
|
|
63
|
+
for commercial packages; see
|
|
64
|
+
[how SimulSI differs](docs/faq.md#how-does-simulsi-compare-with-other-tools).
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
SimulSI is not on PyPI yet; install from source (Python 3.11+):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/Yashjindal11/simulsi.git && cd simulsi
|
|
72
|
+
python -m venv .venv
|
|
73
|
+
.venv/bin/pip install -e . # core
|
|
74
|
+
.venv/bin/pip install -e ".[viz]" # + matplotlib plots
|
|
75
|
+
.venv/bin/pip install -e ".[all]" # + pandas, Parquet, matplotlib, Plotly
|
|
76
|
+
.venv/bin/pip install -e ".[dev]" # everything needed to run the tests
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Command line
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
simulsi init my-study # starter model.py + experiment.yaml
|
|
83
|
+
simulsi validate my-study/experiment.yaml # schema check + model smoke run
|
|
84
|
+
simulsi run examples/queue.py -p servers=3 # one replication, metrics table
|
|
85
|
+
simulsi experiment my-study/experiment.yaml # scenarios x replications, comparison, saved results
|
|
86
|
+
simulsi analyze my-study/results/service-desk --precision 0.05
|
|
87
|
+
simulsi visualize my-study/results/service-desk --out plots
|
|
88
|
+
simulsi benchmark # events/sec on this machine
|
|
89
|
+
simulsi ui my-study/results/service-desk # local dashboard on 127.0.0.1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Experiments are described in YAML - data only, validated against a strict
|
|
93
|
+
schema:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
model: model.py:service_desk
|
|
97
|
+
simulation: {seed: 42, duration: 480}
|
|
98
|
+
experiment: {replications: 30, workers: 4}
|
|
99
|
+
parameters: {arrival_rate: 0.9}
|
|
100
|
+
scenarios:
|
|
101
|
+
- {name: high_demand, parameters: {arrival_rate: 1.3}}
|
|
102
|
+
- {name: extra_server, parameters: {servers: 3}}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Examples
|
|
106
|
+
|
|
107
|
+
| Example | Shows |
|
|
108
|
+
|---|---|
|
|
109
|
+
| [`queue.py`](examples/queue.py) | Minimal M/M/c model checked against Erlang C |
|
|
110
|
+
| [`bank_queue.py`](examples/bank_queue.py) | Reneging customers, staffing scenarios, replication advice |
|
|
111
|
+
| [`hospital.py`](examples/hospital.py) | Priority triage, several resources, service levels |
|
|
112
|
+
| [`warehouse.py`](examples/warehouse.py) | Time-varying demand, picking/packing buffers, backlog |
|
|
113
|
+
| [`manufacturing.py`](examples/manufacturing.py) | Breakdowns with a repair crew, blocking, cost model |
|
|
114
|
+
| [`transportation.py`](examples/transportation.py) | Shuttle loop, boarding capacity, left-behind passengers |
|
|
115
|
+
| [`aviation.py`](examples/aviation.py) | Synthetic airport gates, taxiway holds, tows, weather disruption |
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
python examples/hospital.py
|
|
119
|
+
python scripts/run_examples.py # all of them, quick mode
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
- [Getting started](docs/getting-started.md) - installation, quickstart, first experiment
|
|
125
|
+
- [Core concepts](docs/concepts.md) - simulation, events, entities, resources, queues, processes, randomness, metrics, disruptions, validation, introspection
|
|
126
|
+
- [Experiments and analysis](docs/experiments.md) - scenarios, experiments, Monte Carlo, statistics, comparison, sensitivity, cost, optimisation
|
|
127
|
+
- [Visualization](docs/visualization.md) - plots and the web dashboard
|
|
128
|
+
- [CLI and configuration](docs/cli.md)
|
|
129
|
+
- [Architecture](docs/architecture.md) - design, module map, performance, limitations
|
|
130
|
+
- [Extending SimulSI](docs/extending.md)
|
|
131
|
+
- [Research workflow](docs/research.md) - reproducibility, provenance, statistical practice
|
|
132
|
+
- [Examples](docs/examples.md) - walkthroughs of the domain examples
|
|
133
|
+
- [FAQ](docs/faq.md) - including how SimulSI compares with other tools
|
|
134
|
+
- [Benchmarks](benchmarks/README.md) - measured numbers and how to reproduce them
|
|
135
|
+
|
|
136
|
+
## Status
|
|
137
|
+
|
|
138
|
+
SimulSI is alpha software (0.x) and the API may still change. It is tested on
|
|
139
|
+
Python 3.11-3.13 (Linux, macOS, Windows in CI) with unit, property-based
|
|
140
|
+
(Hypothesis), statistical, integration, CLI and performance tests - including
|
|
141
|
+
checks of simulated M/M/c queues against closed-form Erlang-C results.
|
|
142
|
+
|
|
143
|
+
## Contributing
|
|
144
|
+
|
|
145
|
+
Issues and pull requests are welcome - see [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
146
|
+
and the [Code of Conduct](CODE_OF_CONDUCT.md). For security reports see
|
|
147
|
+
[SECURITY.md](SECURITY.md).
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
[MIT](LICENSE) © 2026 Yash Jindal
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
python benchmarks/run_benchmarks.py # full suite, ~1 minute
|
|
5
|
+
python benchmarks/run_benchmarks.py --quick # 10k / 100k only
|
|
6
|
+
simulsi benchmark # same measurements from the CLI
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The script writes [`results/latest.json`](results/latest.json) (raw numbers
|
|
10
|
+
plus the environment) and [`results/latest.md`](results/latest.md).
|
|
11
|
+
|
|
12
|
+
## What is measured
|
|
13
|
+
|
|
14
|
+
| Benchmark | Description | Size means |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `events` | Pure engine overhead: callback events in 100 interleaved chains with exponential delays (heap push/pop, clock, dispatch). | events |
|
|
17
|
+
| `processes` | An M/M/2 queue written with generator processes, a resource with contention, and metrics: about 3.85 events per customer. | customers |
|
|
18
|
+
| `experiment(workers=N)` | 16 replications of the built-in M/M/1 model (20,000 time units each), serial and in worker processes. | replications |
|
|
19
|
+
| `peak_memory_mb` | `tracemalloc` peak during a separate run (sizes up to 100k only, because tracing slows the run). | |
|
|
20
|
+
|
|
21
|
+
## Results
|
|
22
|
+
|
|
23
|
+
Measured on 2026-10-02 on the development machine. These are single
|
|
24
|
+
measurements, not averages over repeated runs; expect some run-to-run
|
|
25
|
+
variation. Re-run the script on your hardware rather than relying on them.
|
|
26
|
+
|
|
27
|
+
- Python 3.12.15 (CPython), NumPy 2.5.3, SimulSI 0.1.0.dev0
|
|
28
|
+
- macOS 26.6.2 on Apple silicon (arm64), 10 logical CPUs
|
|
29
|
+
|
|
30
|
+
| name | size | events | seconds | events/s | peak MB |
|
|
31
|
+
|---|---:|---:|---:|---:|---:|
|
|
32
|
+
| events | 10,000 | 10,000 | 0.023 | 437,190 | 0.02 |
|
|
33
|
+
| events | 100,000 | 100,000 | 0.228 | 438,656 | 0.02 |
|
|
34
|
+
| events | 1,000,000 | 1,000,000 | 2.281 | 438,466 | - |
|
|
35
|
+
| processes | 10,000 | 38,501 | 0.154 | 250,000 | 0.31 |
|
|
36
|
+
| processes | 100,000 | 385,581 | 1.595 | 241,692 | 0.54 |
|
|
37
|
+
| processes | 1,000,000 | 3,850,935 | 16.34 | 235,737 | - |
|
|
38
|
+
| experiment (1 worker) | 16 | 1,119,489 | 4.59 | 244,072 | - |
|
|
39
|
+
| experiment (2 workers) | 16 | 1,119,489 | 3.82 | 293,357 | - |
|
|
40
|
+
| experiment (4 workers) | 16 | 1,119,489 | 3.40 | 329,285 | - |
|
|
41
|
+
|
|
42
|
+
## Observations
|
|
43
|
+
|
|
44
|
+
* Throughput is flat from 10k to 1M events: the heap is O(log n) and
|
|
45
|
+
finished processes and timeouts are freed by reference counting. An
|
|
46
|
+
earlier version kept a reference cycle per timeout, so the cyclic garbage
|
|
47
|
+
collector slowed long runs by about 30%. That was found with this suite and
|
|
48
|
+
fixed.
|
|
49
|
+
* Memory stays small because statistics are incremental. Keeping raw
|
|
50
|
+
observations (`keep_values`), time series (`record_series`), entity
|
|
51
|
+
histories or an event log (`trace=True`) costs memory proportional to run
|
|
52
|
+
length.
|
|
53
|
+
* Parallel speed-up is modest here (about 1.35x with 4 workers): each
|
|
54
|
+
replication takes about 0.3 s, while starting a worker process with the
|
|
55
|
+
`spawn` method (macOS, Windows) and importing NumPy/SciPy costs about a
|
|
56
|
+
second. Longer replications parallelise better. Results are identical to
|
|
57
|
+
serial runs either way (tested).
|
|
58
|
+
* `tests/performance/test_performance.py` guards against regressions with
|
|
59
|
+
generous floors (about 10x below these numbers) and a linear-scaling check.
|