← Continuous-Time Markov Chains

04

Selecting infection, progression or recovery events

Once the waiting time has been generated, the CTMC must decide which of the currently possible biological events causes the next jump.

Keep “when?” and “which?” separate

When?

The total rate \(a_0\) determines the exponential waiting time.

Completed in Lesson 3

Which?

Each event's rate as a proportion of \(a_0\) determines its conditional selection probability.

This lesson

This page assumes that a jump is about to occur. It selects the event type but does not yet update the state.

Scenario: three competing SEIR events

At the current state:

\[ (S,E,I,R)=(990,5,5,0), \qquad N=1000, \]

use \(\beta=0.3\), \(\sigma=0.2\) and \(\gamma=0.1\) per day.

Infection

\[a_1=\beta SI/N=1.485.\]

Progression

\[a_2=\sigma E=1.000.\]

Recovery

\[a_3=\gamma I=0.500.\]

The total rate is:

\[ a_0=a_1+a_2+a_3=2.985\text{ events/day}. \]

Normalise rates into event probabilities

Given that the next jump occurs, event \(k\) is selected with probability:

\[ \Pr(\text{event }k\mid\text{a jump occurs}) = \frac{a_k}{a_0}. \]

Therefore:

\[ \begin{aligned} p_{\mathrm{infection}}&=1.485/2.985\approx0.4975,\\ p_{\mathrm{progression}}&=1.000/2.985\approx0.3350,\\ p_{\mathrm{recovery}}&=0.500/2.985\approx0.1675. \end{aligned} \]

The rates have units of events per day, but the units cancel in each ratio. The resulting event probabilities are dimensionless and sum to 1.

Why there is no “no-change event” here

This selection is conditional on a CTMC jump occurring. Therefore one of the positive-rate biological events must be selected.

Fixed-step DTMCEvent-driven CTMC
A fixed step may contain no event, so no change is a transition category.The exponential waiting time already represents how long the state remains unchanged.
Event probabilities plus no-change probability sum to 1.Conditional probabilities of currently possible events sum to 1.

Adding a no-change category to the conditional CTMC event selection would double-count waiting.

Construct cumulative intervals

Generate \(U\sim\operatorname{Uniform}(0,1)\) and place the conditional probabilities beside one another:

Uniform intervalLengthSelected event
\(0\le U<0.4975\)0.4975Infection
\(0.4975\le U<0.8325\)0.3350Progression
\(0.8325\le U<1\)0.1675Recovery

The second boundary is cumulative:

\[ 0.8325 = p_{\mathrm{infection}} + p_{\mathrm{progression}}. \]

Translate the intervals into Python

if u < p_infection:
    event = "infection"
elif u < p_infection + p_progression:
    event = "progression"
else:
    event = "recovery"

Reaching elif already means the infection condition was false. Reaching else means the uniform value lies in the remaining recovery interval.

The event order is not biologically important. Another order gives the same event probabilities if its cumulative boundaries are constructed consistently.

Why larger rates are selected more often

The interval assigned to an event has length \(a_k/a_0\). Therefore an event with twice the rate receives twice the interval length and is selected approximately twice as often over many repetitions at the same state.

This does not mean it must occur in any particular single selection. A low-rate event can still be selected.

Boundary and zero-rate events

If \(S=0\)

Infection rate is zero, so the infection interval has zero length.

If \(E=0\)

Progression rate is zero, so progression cannot be selected.

If \(I=0\)

Infection and recovery rates are zero, but progression may remain possible when \(E>0\).

If every event rate is zero, then \(a_0=0\). No event can be selected and the state is absorbing. The program must stop before dividing by \(a_0\).

Conditions for valid event selection

Interactive Python laboratory

The code selects one event and then repeats the selection 20,000 times without changing the state, solely to verify that empirical event proportions approach the conditional probabilities.

Interactive PythonSelect one CTMC event type

Output

Run the code to see the result.

Understand the new code

CodeMeaning
rates / total_rateNormalises rates into dimensionless conditional event probabilities.
np.cumsum(probabilities)Calculates cumulative upper interval boundaries.
counts[event] += 1Adds one to the count belonging to the selected event name.
np.isclose(...)Checks a floating-point probability sum using a small numerical tolerance.

Biological interpretation

At this state, infection has the largest transition rate and therefore the largest conditional probability of being the next event. Progression is the next most likely, and recovery has the smallest interval.

The repeated selections keep the state fixed only to verify the rate-ratio rule. A real CTMC simulation updates the state after one selected event and then recalculates every rate before proceeding.

What this lesson has—and has not—done

You can now:

  • normalise competing event rates by their total;
  • interpret the result as event type conditional on a jump;
  • construct cumulative uniform intervals;
  • handle zero-rate and zero-total-rate cases; and
  • verify selections using repeated fixed-state experiments.

Not yet: Lesson 5 combines one exponential waiting time, one event selection and the corresponding compartment update to program one complete CTMC event.