Finding homology when the sequence has changed
We searched a genome for exact matches to sequences of interest.
CGATGCATGC
ATG <- match!
Every method we built — linear search, \(k\)-mer dictionary, suffix array — depends on an exact character-for-character match.
Two copies of the same gene in two individuals or species are often not identical
ACGTCA
ACTGA
Are these related? Which positions correspond to which?
The moment evolution edits a sequence, exact matching stops working.
Two sequences are homologous if they are descended from a common ancestral sequence.
This is a statement about history, not about similarity.
Aligning two sequences means proposing, for every column, which nucleotide residues descend from the same ancestral residue.
A C G T C A
A C - T G A
An alignment is a hypothesis about a series of evolutionary events
A C G T C A
A C - T G A
We don’t know if G was inserted in the top sequence or deleted from the bottom sequence.
So, we call it an indel
Evolutionary inference. We cannot learn about evolutionary history without assuming which positions correspond. Every molecular evolutionary analysis starts from an alignment!
Locating a sequence. E.g., where in the genome did this read come from? Exact search fails on sequencing errors and biological variation.
Transferring knowledge. A new gene of unknown function is compared to genes of known function. The inference is, similar sequence, shared ancestry, probably shared function.
Two sequences at a time.
ACGTCA
AC-TGA
Tractable and exactly solvable.
Many sequences at once.
ACGTCA
AC-TGA
ACGT-A
AGGTCA
What we often want for analysis, but requires heuristics
Exact multiple alignment of \(N\) sequences means filling an \(N\)-dimensional table. This is infeasible beyond a handful of sequences.
Align the sequences end to end.
Assumes homology runs the full length of both.
Find the best-matching region and ignore the rest.
Assumes homology is confined to a subsequence.
This is a biological assumption, not a technical preference.
E.g., Aligning two homologs of the same short gene? Use global.
E.g., Aligning a conserved domain in two otherwise unrelated proteins? Use local.
Recall from our algorithms lecture: BLAST1 is a heuristic. It finds exact \(k\)-mer seeds, then extends only around those.
BLAST can miss an optimal alignment. It is used billions of times a year because an approximate answer today is better than an exact answer in 9 years.
Both are dynamic programming algorithms, the strategy we used to compute Fibonacci numbers
A C G T C A
A C - T G A
A C G T C A
A C T G A -
Both are valid hypotheses. We need a way to choose.
An objective function: a rule that assigns a score to any alignment, so “best” means something specific.
Score each column independently, then add them up:
| Column | Score |
|---|---|
| Match | \(+1\) |
| Mismatch | \(-1\) |
| Gap | \(-2\) |
A C G T C A
A C - T G A
+1 +1 -2 +1 -1 +1 = 1
A C G T C A
A C T G A -
+1 +1 -1 -1 -1 -2 = -3
The left alignment wins, under this scoring scheme.
The algorithm is guaranteed to find a best-scoring alignment. It is not guaranteed to find the historically correct one.
The number of possible global alignments of two sequences of length \(n\):
| \(n\) | Alignments |
|---|---|
| 5 | 1,683 |
| 10 | \(\approx 8 \times 10^{6}\) |
| 100 | \(> 10^{75}\) |
Exhaustive search becomes impossible quickly!
We need to find the best alignment without looking at all of them
The best alignment of ACGTCA and ACTGA ends in one of three ways:
A aligned with A (match or mismatch)A aligned with a gapAWhichever it is, the rest of the alignment must itself be the best alignment of the two shorter sequences that remain.
A larger problem made of smaller versions of itself, solved once and reused
\[ F(i,j) = \max \begin{cases} F(i-1,\,j-1) + s(A_i, B_j) & \text{(match/mismatch)}\\ F(i-1,\,j) + g & \text{(gap in Seq }B)\\ F(i,\,j-1) + g & \text{(gap in Seq }A) \end{cases} \]
\(F(i,j)\) is the score of the best alignment of the first \(i\) residues of Sequence \(A\) with the first \(j\) residues of Sequence \(B\).
Every cell depends only on cells above and to the left, so we can fill the table in one pass.
\(A\) = ACGTCA down the rows, \(B\) = ACTGA across the columns.
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | -6 | -8 | -10 |
| A | -2 | |||||
| C | -4 | |||||
| G | -6 | |||||
| T | -8 | |||||
| C | -10 | |||||
| A | -12 |
Row 0 and Column 0 are alignments against nothing but gaps, so they are just multiples of the gap penalty.
\(F(1,1)\): best alignment of A with A
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | -6 | -8 | -10 |
| A | -2 | ? | ||||
| C | -4 | |||||
| G | -6 | |||||
| T | -8 | |||||
| C | -10 | |||||
| A | -12 |
| From | Calculation | Score |
|---|---|---|
Diagonal (A with A, match) |
0 + 1 | 1 |
| Up (gap in \(B\)) | -2 + -2 | -4 |
| Left (gap in \(A\)) | -2 + -2 | -4 |
Take the maximum: \(F(1,1) = 1\)
\(F(3,2)\): best alignment of ACG with AC
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | |||
| A | -2 | 1 | -1 | |||
| C | -4 | -1 | 2 | |||
| G | -6 | -3 | ? | |||
| T | ||||||
| C | ||||||
| A |
| From | Calculation | Score |
|---|---|---|
Diagonal (G with C, mismatch) |
-1 + -1 | -2 |
| Up (gap in \(B\)) | 2 + -2 | 0 |
| Left (gap in \(A\)) | -3 + -2 | -5 |
\(F(3,2) = 0\), from above: the G is aligned to a gap.
This one cell is where the indel in our final alignment gets decided.
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | -6 | -8 | -10 |
| A | -2 | 1 | -1 | -3 | -5 | -7 |
| C | -4 | -1 | 2 | 0 | -2 | -4 |
| G | -6 | -3 | 0 | 1 | 1 | -1 |
| T | -8 | -5 | -2 | 1 | 0 | 0 |
| C | -10 | -7 | -4 | -1 | 0 | -1 |
| A | -12 | -9 | -6 | -3 | -2 | 1 |
The bottom-right cell is the score of the best global alignment: 1.
Every cell was computed from cells already filled. No cell was computed twice.
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | -6 | -8 | -10 |
| A | -2 | 1 | -1 | -3 | -5 | -7 |
| C | -4 | -1 | 2 | 0 | -2 | -4 |
| G | -6 | -3 | 0 | 1 | 1 | -1 |
| T | -8 | -5 | -2 | 1 | 0 | 0 |
| C | -10 | -7 | -4 | -1 | 0 | -1 |
| A | -12 | -9 | -6 | -3 | -2 | 1 |
We know the best score (1), but we do not know the alignment that achieves it.
| – | A | C | T | G | A | |
|---|---|---|---|---|---|---|
| – | 0 | -2 | -4 | -6 | -8 | -10 |
| A | -2 | 1 | -1 | -3 | -5 | -7 |
| C | -4 | -1 | 2 | 0 | -2 | -4 |
| G | -6 | -3 | 0 | 1 | 1 | -1 |
| T | -8 | -5 | -2 | 1 | 0 | 0 |
| C | -10 | -7 | -4 | -1 | 0 | -1 |
| A | -12 | -9 | -6 | -3 | -2 | 1 |
Start at the bottom-right and walk backward, asking at each cell: which of the three directions did the score come from?
Seq A: A C G T C A
Seq B: A C - T G A
Score: +1 +1 -2 +1 -1 +1 = 1
Two 100,000-bp sequences: \(10^{10}\) cells, about 40 GB at 4 bytes each.
Optimal alignment is doable for genes, but not genomes.
This is why read mappers index instead of aligning each read to the genome.
A = TTTTACGTCA
B = ACGTCAGGGG
They share ACGTCA, but it sits at opposite ends.
What does the Needleman-Wunsch algo do?
T T T T A C G T C A
A C G T C A G G G G
Score: \(-6\). No gaps, and the shared region is missed!
ACGTCA would require eight gaps: \(-16\), plus \(+6\) for the matches, so \(-10\)The algorithm did not fail. We asked the wrong question! We assumed homology runs the full length.
Three changes to Needleman-Wunsch:
| – | A | C | G | T | C | A | G | G | G | G | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| – | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| A | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| C | 0 | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| G | 0 | 0 | 0 | 3 | 1 | 0 | 0 | 1 | 1 | 1 | 1 |
| T | 0 | 0 | 0 | 1 | 4 | 2 | 0 | 0 | 0 | 0 | 0 |
| C | 0 | 0 | 1 | 0 | 2 | 5 | 3 | 1 | 0 | 0 | 0 |
| A | 0 | 1 | 0 | 0 | 0 | 3 | 6 | 4 | 2 | 0 | 0 |
\[ F(i,j) = \max \begin{cases} 0 \\ F(i-1,\,j-1) + s(A_i, B_j)\\ F(i-1,\,j) + g\\ F(i,\,j-1) + g \end{cases} \]
Mostly zeros, with one diagonal ridge climbing to 6.
A C G T C A
A C G T C A
Score 6, positions 5–10 of \(A\) against positions 1–6 of \(B\).
Use global when
You believe the sequences are homologous along their whole length
Use local when
You believe homology is confined to a region, or the sequences differ a lot in length
Nothing in either algorithm “knows” what a nucleotide is.
The only place nucleotides appear is \(s(A_i, B_j)\).
Every multiple sequence alignment tool is an approximation built upon the algorithm we just walked through.
You will build a global aligner from scratch:
score_alignment: Score a pair of aligned sequencesget_dotplot: Visualize the homology before any aligningfill_scoring_matrix: The Needleman-Wunsch tabletraceback_alignment: Turn the table into an alignmentWatch for
The dotplot of the two sequences from the “when global fails” slide. You will be able to see why the global algorithm made the choice it did.
I used Anthropic’s Claude (Opus 5 model) to generate a draft of these slides.