Skip to content
Part IA Lent Term

The Viterbi Decoding Algorithm

Purpose

Viterbi finds the single most likely hidden-state sequence q1,q2,,qTq_1^*, q_2^*, \ldots, q_T^* given an observation sequence o1,o2,,oTo_1, o_2, \ldots, o_T. It is a dynamic programming algorithm: at each timestep, for each state, it stores the best path probability reaching that state and a backpointer.

Components

δj(t)\delta_j(t): the probability of the most likely path reaching state jj at time tt, accounting for observations o1o_1 through oto_t.

ψj(t)\psi_j(t): the backpointer — which state at t1t-1 produced the best path to state jj at time tt.

Algorithm

Initialisation (t=1t = 1)

For each state jj:

δj(1)=πjbj(o1)ψj(1)=0\delta_j(1) = \pi_j \cdot b_j(o_1) \qquad \psi_j(1) = 0

Recursion (t=2,3,,Tt = 2, 3, \dots, T)

For each state jj:

δj(t)=maxi[δi(t1)aijbj(ot)]\delta_j(t) = \max_i \big[ \delta_i(t-1) \cdot a_{ij} \cdot b_j(o_t) \big] ψj(t)=argmaxi[δi(t1)aij]\psi_j(t) = \arg\max_i \big[ \delta_i(t-1) \cdot a_{ij} \big]

Note: bj(ot)b_j(o_t) is the same for all ii, so it can be pulled outside the max. The argmax\arg\max is over δi(t1)aij\delta_i(t-1) \cdot a_{ij} only.

Termination (t=Tt = T)

Best path probability: P=maxiδi(T)P^* = \max_i \delta_i(T)

Final state: qT=argmaxiδi(T)q_T^* = \arg\max_i \delta_i(T)

Backtracking (t=T1t = T-1 down to 11)

qt=ψqt+1(t+1)q_t^* = \psi_{q_{t+1}^*}(t+1)

Read the backpointer chain backwards to reconstruct the optimal state sequence.

Trellis Layout

Draw a grid: rows = states, columns = timesteps. Fill each cell with δj(t)\delta_j(t) and ψj(t)\psi_j(t). Circle the maximum in each column. Draw arrows from each cell to its backpointer source. After termination, trace arrows backwards from the final state.

Log-Space Implementation

In practice, use log-probabilities to prevent underflow:

δj(t)=maxi[δi(t1)+logaij+logbj(ot)]\delta_j(t) = \max_i \big[ \delta_i(t-1) + \log a_{ij} + \log b_j(o_t) \big]

Products become sums. The argmax\arg\max result is identical. For exam purposes, you can work in either space — log is safer for long sequences.

Worked Example: 2-State Model, 3 Timesteps

Given: S={1,2}S = \{1, 2\}, V={A,B}V = \{A, B\}, observations = [A,B][A, B]

π=[0.6,0.4]A=[0.70.30.40.6]B=[0.50.50.90.1]\pi = [0.6, 0.4] \quad A = \begin{bmatrix} 0.7 & 0.3 \\ 0.4 & 0.6 \end{bmatrix} \quad B = \begin{bmatrix} 0.5 & 0.5 \\ 0.9 & 0.1 \end{bmatrix}

t=1t = 1, observation AA

δ1(1)=0.6×0.5=0.30ψ1(1)=0\delta_1(1) = 0.6 \times 0.5 = 0.30 \quad \psi_1(1) = 0 δ2(1)=0.4×0.9=0.36ψ2(1)=0\delta_2(1) = 0.4 \times 0.9 = 0.36 \quad \psi_2(1) = 0

Best at t=1t=1: state 2, δ=0.36\delta = 0.36.

t=2t = 2, observation BB

For state 1: δ1(2)=max[0.30×0.7×0.5,  0.36×0.4×0.5]=max[0.105,0.072]=0.105\delta_1(2) = \max[0.30 \times 0.7 \times 0.5,\; 0.36 \times 0.4 \times 0.5] = \max[0.105, 0.072] = 0.105 ψ1(2)=1\psi_1(2) = 1

For state 2: δ2(2)=max[0.30×0.3×0.1,  0.36×0.6×0.1]=max[0.009,0.0216]=0.0216\delta_2(2) = \max[0.30 \times 0.3 \times 0.1,\; 0.36 \times 0.6 \times 0.1] = \max[0.009, 0.0216] = 0.0216 ψ2(2)=2\psi_2(2) = 2

Best at t=2t=2: state 1, δ=0.105\delta = 0.105.

Termination and Backtrack

P=max(0.105,0.0216)=0.105P^* = \max(0.105, 0.0216) = 0.105, final state q2=1q_2^* = 1. Backpointer: ψ1(2)=1\psi_1(2) = 1, so q1=1q_1^* = 1. Optimal path: [1,1][1, 1].

Summary

StepFormula
Initδj(1)=πjbj(o1)\delta_j(1) = \pi_j \cdot b_j(o_1)
Recursionδj(t)=maxi[δi(t1)aijbj(ot)]\delta_j(t) = \max_i [\delta_i(t-1) \cdot a_{ij} \cdot b_j(o_t)]
Backpointerψj(t)=argmaxi[δi(t1)aij]\psi_j(t) = \arg\max_i [\delta_i(t-1) \cdot a_{ij}]
TerminationP=maxiδi(T)P^* = \max_i \delta_i(T), qT=argmaxiδi(T)q_T^* = \arg\max_i \delta_i(T)
Backtrackqt=ψqt+1(t+1)q_t^* = \psi_{q_{t+1}^*}(t+1)
Log formSums instead of products, avoids underflow

Past paper questions: y2022p3q9, y2024p3q8, y2025p3q9