Monte Carlo & Discrete-Event Simulation
Experimenting with systems on a computer. Learn when to simulate, random-number generation and sampling from distributions, Monte Carlo for risk and uncertainty, discrete-event simulation (entities, events, queues, clocks), model building, verification and validation, warm-up, replications and confidence intervals, output analysis and scenario comparison, and simulation software — with Python for a project-risk Monte Carlo and a DES queue.
Real systems are too complex, random and interconnected for closed-form formulas: a hospital with shared resources, a factory with breakdowns, a supply chain with variable lead times. Simulation builds a computer model that mimics the system's behaviour over time so you can test 'what if?' without disrupting reality.
Monte Carlo simulation samples uncertain inputs many times to estimate distributions of outcomes (risk). Discrete-event simulation (DES) steps through events — arrivals, service starts, completions, breakdowns — to measure throughput, waiting and utilisation.
An analogy
Simulation is a flight simulator for operations: you can crash the hospital (overload it) a thousand times on the computer and learn how to prevent it, without harming a single patient.
When to simulate
Use simulation when the system has randomness, interactions and constraints that analytical models can't capture, when experimenting on the real system is expensive or risky, and when you need to compare design alternatives (layouts, staffing, policies). Don't simulate when a simple formula answers the question.
Monte Carlo simulation
Replace uncertain inputs with probability distributions (triangular, normal, lognormal, empirical), sample them thousands of times, compute the output each time, and analyse the output distribution: mean, percentiles (P50, P90), probability of meeting a target. Used for project schedules and costs, financial risk, reliability and tolerance stack-up.
Discrete-event simulation
DES building blocks:
- Entities — customers, parts, patients moving through the system
- Resources — servers, machines, staff with capacities and schedules
- Events — arrivals, starts, finishes, breakdowns; a future-event list and simulation clock
- Queues and routing logic, attributes and statistics collection
- Software: Arena, Simio, AnyLogic, FlexSim, SimPy (Python)
Doing it properly
Verification (the model does what you intended — trace, animate, test extremes) and validation (the model represents reality — compare with historical data, face validity). Remove initialisation bias with a warm-up period, run independent replications, report confidence intervals, use common random numbers when comparing alternatives, and design experiments (factorial, optimisation via simulation). Document assumptions — a simulation is only as good as its input data.
Formulas
- Monte Carlo estimate:
E[f(X)] ≈ (1/N)·Σ f(xᵢ) - Standard error:
SE = s/√N (halve error → 4× samples) - Confidence interval:
x̄ ± t_{α/2, n−1}·s/√n - Inverse-transform sampling:
x = F⁻¹(U), U ~ Uniform(0,1); exponential: x = −ln(U)/λ - Replications needed:
n ≈ (t·s/h)² for half-width h
Worked example: Sampling an exponential
Given: λ = 4/h, U = 0.30
Find: Inter-arrival time.
- x = −ln(0.30)/4
Answer: 0.301 h ≈ 18 min
Worked example: Triangular mean
Given: Tri(4, 6, 10)
Find: Mean.
- (4 + 6 + 10)/3
Answer: 6.67 days (> mode 6)
Worked example: Replications
Given: Pilot: s = 3 min for mean wait; want ±1 min at 95%
Find: n.
- (1.96 × 3/1)²
Answer: ≈ 35 replications
Monte Carlo project risk and a discrete-event queue
import random, statistics
random.seed(42)
# Monte Carlo: project completion time with three uncertain tasks (triangular durations)
tasks = [(4, 6, 10), (3, 5, 9), (5, 7, 12)] # (min, mode, max) days, in series
N = 20000
totals = sorted(sum(random.triangular(a, c, b) for a, b, c in tasks) for _ in range(N))
mean = statistics.mean(totals)
p90 = totals[int(0.9 * N)]
print(f"deterministic (modes) = {sum(t[1] for t in tasks)} days")
print(f"simulated mean = {mean:.2f} days, P90 = {p90:.2f} days, P(<= 20 days) = {sum(t <= 20 for t in totals)/N:.3f}")
# Discrete-event single-server queue (M/M/1, lam=4/h, mu=5/h)
random.seed(1)
t = server_free = 0.0; waits = []
for i in range(20000):
t += random.expovariate(4.0)
start = max(t, server_free)
waits.append(start - t)
server_free = start + random.expovariate(5.0)
print(f"DES mean wait {statistics.mean(waits)*60:.1f} min (theory Wq = {4/(5*(5-4))*60:.0f} min)")
# deterministic (modes) = 18 days
# simulated mean = 20.33 days, P90 = 23.36 days, P(<= 20 days) = 0.460
# DES mean wait 43.7 min (theory Wq = 48 min)Planning with 'most likely' durations (18 days) is optimistic: right-skewed task times make the expected project length 20.3 days and only a 46% chance of finishing within 20 — the reason projects run late. The DES queue converges slowly towards theory at 80% utilisation because waits are highly correlated; real studies use warm-up periods, several replications and confidence intervals.
Common mistakes
- Wrong: Using averages instead of distributions. — Right: Variability drives queues and delays (flaw of averages).
- Wrong: One simulation run as the answer. — Right: Multiple replications and confidence intervals.
- Wrong: Including start-up (empty) period in statistics. — Right: Use a warm-up period for steady-state studies.
Applications
- Healthcare: Emergency department and ICU capacity studies.
- Manufacturing: Line design, buffer sizing, AGV fleets.
- Project management: Schedule and cost risk (Monte Carlo).
- Logistics: Warehouse, port and airport operations.
Key takeaways
- Simulate when randomness and interactions defeat formulas.
- Monte Carlo → risk distributions (P50/P90).
- DES: entities, resources, events, clock.
- Verify, validate, warm up, replicate, report CIs.
Going further
- Agent-based simulation: Autonomous agents with behaviours (pedestrians, markets).
- Simulation optimisation: OptQuest, ranking & selection, Bayesian optimisation.
- Digital twins: Simulation fed with live data for real-time decisions.