← Continuous-Time Markov Chains

11

Simulating many continuous-time trajectories

One CTMC path is one possible epidemic history. Repeating the simulation independently reveals the range, frequency and time-dependent variability of possible histories.

Scenario and new question

Consider an SIR epidemic in a population of 200, starting with one infectious person. Instead of asking “what happened in one run?”, we ask “what patterns occur across many runs under the same biological assumptions?”

Same model

Every trajectory uses the same initial state and parameters.

Independent randomness

Each trajectory consumes new random draws and represents a different possible epidemic.

Ensemble

The collection of trajectories approximates the model’s distribution of outcomes.

Why trajectories cannot be averaged event by event

CTMC jump times differ across runs. Event 20 might occur on day 3 in one run and day 18 in another; some paths may already be extinct. Therefore, “the average state at event 20” is not the average state on a common biological date.

Solution: observation grid. Choose common times such as days 0, 1, 2, …, 100. For each trajectory and each grid time, use the state immediately after the most recent jump. This does not change the CTMC; it only observes its piecewise-constant path at common times.

From irregular paths to a rectangular array

\[M_{r,k}=I_r(t_k),\qquad r=1,\ldots,R,\quad k=0,\ldots,m.\]

Rows represent independent trajectories and columns represent common observation times. Column summaries then answer time-specific questions.

Interactive Python laboratory

Run 200 independent SIR trajectories. The code keeps exact jump paths for selected examples, aligns every path to a daily grid, and displays sample paths together with the ensemble mean and central 90% interval.

Interactive PythonMany CTMC trajectories

Output

Run the code to see the result.

Understand the new Python

CodeMeaning
def simulate_sir(...)Packages one complete trajectory into a reusable function.
for run in range(number_of_runs)Repeats the simulation the requested number of times.
np.searchsorted(...)Finds the most recent jump at or before each observation time.
axis=0Summarises down the runs separately at every time column.
np.quantile(..., 0.05)Finds a value with approximately 5% of simulated values below it.

Mean path is not a typical individual path

The ensemble mean may be non-integer and smooth even though every actual CTMC path contains integer jumps. It averages across epidemics at each time. It should not be presented as one simulated epidemic.

The shaded interval describes the spread of simulated \(I(t)\) values, not uncertainty about the calculated mean itself.

Reproducibility and independence

A fixed seed makes the whole experiment reproducible. The random-number generator is created once, outside the loop. Each run then receives new draws from that generator. Recreating it with the same seed inside the loop would incorrectly reproduce the identical path every time.

What this lesson adds

You can now separate a single path from an ensemble, write a reusable CTMC function, generate independent trajectories, align irregular jump paths on common observation times, and calculate time-specific empirical summaries. The next lesson defines events such as early extinction and major outbreak before estimating their probabilities.