The likelihood of a tree, and the ancestors within it
Any model of sequence evolution is a rate matrix \(Q\), and \(P(t) = e^{Qt}\) gives us its transition probabilities
With \(P(t)\), we calculated the likelihood of the divergence between two sequences
But most questions in biology involve many sequences, related by a tree
| Term | Meaning |
|---|---|
| Tip nodes | The sequences we have |
| Internal nodes | Their ancestors (no data!) |
| Branch | Line connecting nodes; a lineage evolving through time |
| Branch length | Expected substitutions per site (like \(t\)) |
| Root | The ancestor of everything |
| Topology | The branching pattern |
| Clade | An ancestor and all its descendants |
Newick format: Parentheses hold descendants; numbers after colons are branch lengths
((Human:0.1,Chimp:0.1)Primates:0.3,(Mouse:0.2,Rat:0.2)Rodents:0.2)Root;
| Index | Name | Children | Length |
|---|---|---|---|
| 0 | Human | 0.1 | |
| 1 | Chimp | 0.1 | |
| 2 | Primates | 0, 1 | 0.3 |
| 3 | Mouse | 0.2 | |
| 4 | Rat | 0.2 | |
| 5 | Rodents | 3, 4 | 0.2 |
| 6 | Root | 2, 5 |
In the exercise, we represent a tree as a list of nodes in postorder
Every node comes after its children, so the root is last
Newick format is named after Newick’s seafood restaurant in Dover, NH, where a committee of phylogeneticists met in 1986 to agree on the format
Unrooted trees with \(n\) tips:1 \(\;1 \times 3 \times 5 \times \cdots \times (2n - 5)\)
| Tips | Unrooted trees | At 1 million trees per second |
|---|---|---|
| 4 | 3 | |
| 10 | 2,027,025 | 2 seconds |
| 15 | \(7.9 \times 10^{12}\) | 92 days |
| 20 | \(2.2 \times 10^{20}\) | 7 million years |
| 24 | \(5.6 \times 10^{26}\) | \(1.8 \times 10^{13}\) years |
We can’t try them all! Programs like IQ-TREE and RAxML use heuristic search: Make small rearrangements, and keep the ones that improve the likelihood
For two sequences, each site needed one lookup. E.g., \(P_{A \rightarrow G}(t)\)
On a tree, we have to add up over every possible combination of bases at the internal nodes
An unrooted tree of 24 genomes has 22 internal nodes:
\(4^{22} \approx 1.8 \times 10^{13}\) combinations, for every site
Question: Is there a way to avoid repeating work?
For each node, from the tips to the root, calculate its conditional likelihoods: \(L_{\text{node}}(i)\) = probability of the data at the tips that descend from the node, if the node has base \(i\)
In doing this, the pruning algorithm follows 3 rules
At each tip node: the conditional likelihood is 1 for the base we observed and 0 for the other three bases
For example:
A” in our data, given the true base is A = 1A” in our data, given the true base is C = 0At each internal node: For each base \(i\), multiply together, over each child, the probability of getting the child’s data if the node has base \(i\):
\[ L_{\text{parent}}(i) = \prod_{\text{children}} \Big[ \sum_{j} P_{ij}(t_{\text{child}}) \, L_{\text{child}}(j) \Big] \]
For example, if the parent (\(i\)) has A and the child (\(j\)) has G, the term in the sum is the probability that A evolved to G along the branch connecting them (\(P_{A\rightarrow G}(t_{\text{child}})\)), times the probability of the data at the tips that descend from the child, if the child has G (\(L_{\text{child}}(G)\))
This is dynamic programming (like Needleman-Wunsch alignment!): Each \(L_{\text{child}}\) is calculated once, and re-used for every base of the parent
At the root, the likelihood of the site is the sum of the conditional likelihoods of the four bases, weighted by the base frequencies:
\(L_{\text{site}} = \sum_{i} \pi_i \, L_{\text{root}}(i)\)
This is a weighted average!
For example:
A: The probability of the root having A (\(\pi_A\)), times the probability of the data at all the tips, if the root has A (\(L_{\text{root}}(A)\))| Node | \(L(\texttt{A})\) | \(L(\texttt{C})\) | \(L(\texttt{G})\) | \(L(\texttt{T})\) |
|---|---|---|---|---|
| Human, Chimp | 1 | 0 | 0 | 0 |
| Mouse, Rat | 0 | 0 | 1 | 0 |
| Primates | 0.8215 | 0.0010 | 0.0010 | 0.0010 |
| Rodents | 0.0034 | 0.0034 | 0.6797 | 0.0034 |
| Root | 0.0266 | 0.0029 | 0.0385 | 0.0029 |
\(L_{\text{site}} = \frac{1}{4}(0.0266 + 0.0029 + 0.0385 + 0.0029) = 0.0177\)
| Name | Pango lineage1 |
|---|---|
| Wuhan | B (the reference genome) |
| B.1 | B.1 |
| Delta | B.1.617.2 |
| Alpha | B.1.1.7 |
| Gamma | P.1 = B.1.1.28.1 |
| Omicron | BA.1.1 = B.1.1.529.1.1 |
Lineage names work like addresses: B.1.1 descends from B.1, which descends from B
| Tree | Log-likelihood | Worse by |
|---|---|---|
| 1: (Wuhan, Delta), (Alpha, Omicron) | −42,433.11 | |
| 2: (Wuhan, Alpha), (Delta, Omicron) | −42,444.08 | 10.96 |
| 3: (Wuhan, Omicron), (Delta, Alpha) | −42,447.15 | 14.04 |
How much does each kind of site favor Tree 1 over Tree 2?
| Kind of site | Sites | Tree 1 − Tree 2 |
|---|---|---|
Two pairs (e.g., AATT) |
4 | +12.49 |
| All four the same | 29,750 | +2.01 |
| One genome differs | 98 | −4.44 |
| Three or more bases | 2 | +0.93 |
| Missing data | 49 | −0.02 |
The conditional likelihoods at the root also give us the probability of each base:
\[ \Pr(\text{root has base } i \mid \text{data}) = \frac{\pi_i \, L_{\text{root}}(i)}{\sum_{k} \pi_k \, L_{\text{root}}(k)} \]
For our example site:
| Base (\(i\)) | \(L_\text{root}(i)\) | \(\Pr(\text{root has base } i \mid \text{data})\) |
|---|---|---|
A |
0.0266 | 0.375 |
C |
0.0029 | 0.042 |
G |
0.0385 | 0.542 |
T |
0.0029 | 0.042 |
Question: But what about the other ancestors?
The maximum likelihood tree of six genomes (JC model)
| Position | Wuhan | B.1 | Delta | Alpha | Gamma | Omicron | B.1 ancestor | B.1.1 ancestor |
|---|---|---|---|---|---|---|---|---|
| 3,037 | C |
T |
T |
T |
T |
T |
T |
T |
| 14,408 | C |
T |
T |
T |
T |
T |
T |
T |
| 23,403 (D614G) | A |
G |
G |
G |
G |
G |
G |
G |
| 28,881–3 | GGG |
GGG |
TGG |
AAC |
AAC |
AAC |
GGG |
AAC |
Every reconstruction has a probability of about 0.9999 or higher
get_tip_names: Loop over a tree’s list of nodesnumber_of_unrooted_trees: Count tree spacetip_likelihoods, combine_children, get_root_likelihoods, site_log_likelihood: Build the pruning algorithm, one rule at a timeroot_state_probabilities and reconstruct_ancestor: Reconstruct the ancestors of SARS-CoV-2 lineagesWatch for
Does rerooting the tree change its likelihood?
I drafted and iterated on these slides in collaboration with Anthropic’s Claude (Opus 5.5 model).