← Continuous-Time Markov Chains

09

Programming a CTMC SEIR model

The SEIR model separates becoming infected from becoming infectious. A newly infected person first enters a random latent period in the exposed compartment.

Scenario: infection with a latent period

A closed population contains 300 people. Initially, 294 are susceptible, 4 are exposed and 2 are infectious. Exposed individuals carry the infection but are not yet infectious in this basic model.

Susceptible
\(S\)
infection →
Exposed
\(E\)
progression →
Infectious
\(I\)
recovery →
Removed
\(R\)
Important distinction: an infection event increases \(E\), not \(I\). Infectious prevalence rises later, only when a progression event moves an exposed person into \(I\).

Three events and their rates

1. Infection

\[(S,E,I,R)\to(S-1,E+1,I,R)\]
\[a_1=\beta\frac{SI}{N}.\]

2. Progression

\[(S,E,I,R)\to(S,E-1,I+1,R)\]
\[a_2=\sigma E.\]

3. Recovery

\[(S,E,I,R)\to(S,E,I-1,R+1)\]
\[a_3=\gamma I.\]

The total rate is \(a_0=a_1+a_2+a_3\). At each jump, Gillespie’s algorithm selects one and only one of these events.

Interpret the progression parameter

Each exposed individual progresses at rate \(\sigma\) per day. Under the Markov assumption, that person’s latent time is exponentially distributed:

\[T_E\sim\operatorname{Exp}(\sigma),\qquad \mathbb E[T_E]=\frac{1}{\sigma}.\]

For \(\sigma=0.20\) per day, the mean latent period is 5 days. This is a mean, not a fixed five-day delay: individual progression times vary randomly.

When has an SEIR epidemic ended?

ConditionCan infection continue?Reason
\(I=0\) but \(E>0\)YesExposed people can progress and create new infectious people.
\(E=0\) but \(I>0\)YesInfectious people can still infect or recover.
\(E=0\) and \(I=0\)NoAll three event rates are zero.

Therefore, the correct biological stopping condition is E == 0 and I == 0, not merely I == 0.

Interactive Python laboratory

Run a complete SEIR epidemic. The program prints event identities that verify the compartment bookkeeping, plots all four state paths, and compares the cumulative infection and progression processes.

Interactive PythonCTMC SEIR model

Output

Run the code to see the result.

Understand the three-event selection

Random intervalSelected event
\(0\le U<a_1/a_0\)Infection
\(a_1/a_0\le U<(a_1+a_2)/a_0\)Progression
\((a_1+a_2)/a_0\le U<1\)Recovery

np.cumsum(rates / total_rate) creates the upper boundaries of these intervals. The final boundary is 1 apart from tiny floating-point rounding.

Why the event-count checks work

Every person entering \(E\) must eventually progress before the simulation ends. Therefore:

\[\text{progressions}=E(0)+\text{infection events}.\]

Likewise, every person entering \(I\) must eventually recover:

\[\text{recoveries}=I(0)+\text{progression events}.\]

These are not extra model assumptions. They are accounting identities for a completed closed SEIR epidemic and useful checks on the program.

Interpret the two plots

The compartment plot shows that the exposed peak can occur before the infectious peak. The exact timing and separation vary between trajectories.

In the cumulative-event plot, infection events usually lead progression events because people must first enter \(E\). The gap represents people currently waiting in the exposed compartment; initial exposed people explain the initial offset in the bookkeeping identity.

Try these experiments

  1. Reduce sigma to 0.10. The mean latent period becomes 10 days; compare the peak times.
  2. Increase sigma to 1.0. Observe how the model approaches faster SIR-like progression.
  3. Use I = 0 but keep E = 4. Confirm that the program does not stop prematurely.
  4. Try several seeds and compare whether the exposed or infectious peak changes more.

What is unique to this lesson?

You have separated infection from infectiousness, interpreted the exponential latent period, selected among three competing events, used the correct SEIR extinction condition, and verified the simulation with event-count identities. The next lesson moves from trajectory simulation to the CTMC generator matrix.