Dynamic programming
Be able to solve optimisation problems by reusing partial results, for instance Viterbi and edit distance.
Prerequisites
- DRecursionrequired
- DTime complexity and big-O notationrequired
Intuition
Dynamic programming solves problems that have two properties:
- Optimal substructure — the best solution is built from the best solutions to subproblems.
- Overlapping subproblems — the same subproblem turns up again and again.
Naive recursion recomputes the same thing exponentially many times. DP stores the partial results and goes from to or better.
Two ways of doing it:
- Memoisation (top-down): ordinary recursion plus a cache. The simplest — often
@functools.cacheis enough. - Tabulation (bottom-up): fill a table in the right order. Faster and without recursion depth.
Code
from functools import cache
import numpy as np
# 1. Edit distance (Levenshtein) — used for spelling correction and evaluation metrics
def edit_distance(a: str, b: str) -> int:
m, n = len(a), len(b)
d = np.zeros((m + 1, n + 1), dtype=int)
d[:, 0] = np.arange(m + 1); d[0, :] = np.arange(n + 1)
for i in range(1, m + 1):
for j in range(1, n + 1):
cost = 0 if a[i-1] == b[j-1] else 1
d[i, j] = min(d[i-1, j] + 1, # delete
d[i, j-1] + 1, # insert
d[i-1, j-1] + cost) # substitute
return int(d[m, n])
print(edit_distance("kitten", "sitting")) # 3
# 2. Viterbi — the most likely hidden sequence (POS tagging, speech recognition)
def viterbi(obs, states, start_p, trans_p, emit_p):
V = [{s: start_p[s] * emit_p[s][obs[0]] for s in states}]
path = {s: [s] for s in states}
for t in range(1, len(obs)):
V.append({}); new_path = {}
for s in states:
p, prev = max((V[t-1][f] * trans_p[f][s] * emit_p[s][obs[t]], f) for f in states)
V[t][s] = p; new_path[s] = path[prev] + [s]
path = new_path
p, last = max((V[-1][s], s) for s in states)
return path[last], p
# 3. Memoisation is often enough
@cache
def fib(n):
return n if n < 2 else fib(n-1) + fib(n-2)
print(fib(100)) # immediately; without the cache: astronomical
Where you meet DP in ML: edit distance in evaluation metrics (WER for speech recognition), Viterbi in sequence labelling and HMMs, beam search as approximate DP, and the CTC loss in speech recognition.
Mastery means
- Solves problems by reusing partial results
- Implements edit distance and Viterbi
- Recognises when DP is applicable
Sign in to do the exercises and build your mastery up.
Sources
- Wikipedia — Dynamisk programmering (CC BY-SA 4.0) — CC BY-SA 4.0
- Wikipedia — Viterbi algorithm (CC BY-SA 4.0) — CC BY-SA 4.0