monte-carlo
GitHub用于执行 PlanExe 模型的蒙特卡洛模拟,通过采样生成输出分布、阈值通过概率及敏感性分析。
Trigger Scenarios
Install
npx skills add PlanExeOrg/PlanExe --skill monte-carlo -g -y
SKILL.md
Frontmatter
{
"name": "monte-carlo",
"description": "Use when the user wants Monte Carlo simulation of a PlanExe model — sampling from bounds to produce output distributions (mean\/std\/percentiles), threshold pass probabilities, and Pearson-correlation sensitivity rankings — given an extract-parameters-from-full JSON, a generate-bounds JSON, a generate-calculations Python module, and optional run settings"
}
Monte Carlo Simulation
Overview
This stage is stochastic — it samples from bounds many times. Contrast with run-scenarios, which evaluates the model deterministically at three points only.
The simulation itself is performed by a Python script (experiments/napkin_math/run_monte_carlo.py), not by the LLM. The script imports calculations.py, draws samples with a seeded NumPy RNG, runs the loop, and writes montecarlo.json. The script is authoritative; this skill is a thin wrapper that locates inputs, builds an optional settings file, and invokes the runner.
Stage 7 of the pipeline described in planexe_simulator/README.md.
When to Use
- User asks to "run Monte Carlo", "sample the bounds", "compute distributions", "estimate gate-pass probability", or "find which inputs drive uncertainty"
- User wants percentile bands (p05/p50/p95) or threshold pass rates (e.g.
P(avoided_events ≥ 10)) - Final stage in the pipeline; only run after
run-scenariosalready shows a sane deterministic model
Not for: regenerating any prior artifact, replacing the deterministic scenario table (use run-scenarios), or claiming causality from sensitivity correlations.
Workflow
-
Get the inputs. Three required, one optional:
- parameters JSON (e.g.
output/v12/parameters.json) - bounds JSON (e.g.
output/v12/bounds.json) - calculations Python module (e.g.
output/v12/calculations.py) - settings JSON (optional —
n_runs,seed,distribution_default,outputs_of_interest,thresholds,gate_probabilities,correlation_groups)
If any required input is missing, ask. If the user wants thresholds or non-default settings, write them to a small JSON file and pass
--settings. - parameters JSON (e.g.
-
Invoke the runner. Requires Python 3.11+ with NumPy:
/opt/homebrew/bin/python3.11 experiments/napkin_math/run_monte_carlo.py \ --parameters <path>/parameters.json \ --bounds <path>/bounds.json \ --calculations <path>/calculations.py \ [--settings <path>/settings.json] \ [--output <path>/montecarlo.json]Default output path is
<dir-of-parameters>/montecarlo.json. The script prints a one-line summary (n_runs, output count, threshold count, warning count) on stdout. -
Report back. Tell the user the output path and the one-line summary. If the user asks for interpretation, read the JSON, then explain — but never replace running the script with hand-computed numbers.
What the runner does (so the LLM can describe results accurately)
The runner does no lexical pattern-matching on id strings, unit strings, or rationale text. Every semantic classification it needs is read verbatim from upstream-declared fields. If a required field is missing, the runner exits with SCHEMA ERROR and names which upstream stage to re-run.
-
Distributions per bounded variable — driven by the bound's
sampling_disciplinefield (required, declared bygenerate-bounds):"fixed"— always returns the single pinned value"bernoulli_gate"— Bernoulli draw with probability fromsettings.gate_probabilities[id]if set, else the bound'sdefault_pass_probability(required, in[0, 1]). Returnshighon pass,lowon fail. Works for any unit — currency tranches, permit toggles, regulatory pass/fail."integer"— sample triangular/uniform, round to nearest integer, re-clamp to[low, high]"fraction"— sample triangular/uniform, clamp to[0, 1]"continuous"— sample triangular/uniform with no extra rounding or clamping beyond[low, high]- Default base distribution: triangular
(low, mode=base, high).distribution_default: "uniform"switches to uniform. - The bound's
non_negative: bool(required) drives whether draws are clamped to>= 0.
-
Output names and units: the runner uses
entry.output_nameandentry.output_unitfrom eachrecommended_first_calculations/derived_questionsentry, declared byextract-parameters-from-full. The runner does not parseformula_hintto recover the name, and does not infer units from id tokens. The LLM is the single authority for both. -
Calculation execution: uses
inspect.signatureon each generated function to pull args from the run's input pool. Order:recommended_first_calculationsfirst, thenderived_questions. Outputs are added to the pool so later functions can depend on them. Missing dependencies / non-finite results / exceptions skip the run for that output (one aggregated warning, not per-run noise). -
Sensitivity: Pearson correlation between each sampled input and each summarized output, top 5 by
|correlation|. Only inputs that vary AND are used directly or indirectly by the output AND have ≥20 finite paired samples are considered.NaNcorrelations becomenull+ warning. -
Thresholds: operators
> >= < <= == !=only. Probability = success_count / valid_count.valid_count == 0→ probabilitynull. -
By default variables are independent.
correlation_groupsis currently parsed but not yet implemented in the runner; if the user passes them, the script will accept the setting and ignore correlation enforcement. Update the runner if correlation is actually needed.
Required upstream schema
For the runner to accept the artifacts, the upstream LLM stages must have emitted:
- Each
bounds.jsonentry —sampling_discipline(string, one offixed | bernoulli_gate | integer | fraction | continuous),non_negative(bool),default_pass_probability(number in[0, 1]whensampling_discipline == "bernoulli_gate", otherwisenull). - Each
recommended_first_calculationsandderived_questionsentry with non-nullformula_hint—output_name(snake_case id of the computed value) andoutput_unit(unit string).
If any required field is missing, the runner exits with SCHEMA ERROR: <message>. Re-run <stage>. and exit code 2. Fix the upstream artifact and re-run; the runner has no fallback path that re-guesses any of these.
Output Shape
{
"valid": true,
"plan_summary": { "plan_name": "...", "plan_type": "..." },
"settings": { "n_runs": 10000, "seed": 12345, "distribution_default": "triangular" },
"outputs": {
"<output_id>": {
"unit": "...",
"count": ..., "missing_count": ...,
"mean": ..., "std": ...,
"min": ..., "p05": ..., "p25": ..., "p50": ..., "p75": ..., "p95": ..., "max": ...
}
},
"thresholds": {
"<output_id>": { "operator": ">=", "value": ..., "success_count": ..., "valid_count": ..., "probability": ... }
},
"sensitivity": {
"<output_id>": { "top_inputs": [ { "id": "...", "correlation": ... } ] }
},
"warnings": [
{ "stage": "monte_carlo", "run": null, "calculation": null, "message": "...", "severity": "WARN" }
]
}
JSON forbids NaN/Infinity — the runner writes null and adds a warning. Identical inputs + identical seed produce a byte-identical output file.
Common Mistakes
| Mistake | Fix |
|---|---|
| Hand-rolling stats inside the LLM response | Run the script. Never produce summary numbers without it. |
| Producing low/base/high tables instead of distributions | Wrong stage — that's run-scenarios. This one samples. |
| Claiming causality from a high Pearson correlation | Sensitivity ≠ causation; only describe directional strength. |
| Treating "0% probability" as impossible | It means 0 of valid_count samples passed; widen bounds or revisit the model. |
Running with python3 when only python3.11 has NumPy |
Use the explicit interpreter path. |
Reference
- Runner (authoritative implementation):
experiments/napkin_math/run_monte_carlo.py - Pipeline overview:
../../README.md, Stage 7 - Companion skills:
../extract-parameters-from-full/SKILL.md,../validate-parameters/SKILL.md,../generate-bounds/SKILL.md,../generate-calculations/SKILL.md,../run-scenarios/SKILL.md - Synthetic fixture exercising every
sampling_discipline(used as the runner smoke test):experiments/napkin_math/tests/fixtures/smoke/parameters.jsonexperiments/napkin_math/tests/fixtures/smoke/bounds.jsonexperiments/napkin_math/tests/fixtures/smoke/calculations.py
Version History
- 846f612 Current 2026-08-20 11:18


