When the algorithm is a table

A cell that has to know where it is

A gap of four characters is usually one event, not four. No recurrence over a single table can charge it that way, because the price of a gap character depends on how the cell above it was reached and a cell holding one number has thrown that away. The repair is three tables, and it costs exactly three times the cells.

Under the unit cost model a gap of four characters costs four, because it is four insertions. Under almost any account of how two strings came to differ, it is one event: a stretch went missing, or a stretch was added, and the length of it is a detail of the same event rather than four separate ones.

An affine gap charge says that directly. A gap of kk characters costs

γ(k)=o+ek\gamma(k) = o + e \cdot k

— an opening price oo paid once, and an extension price ee paid per character. Set o=0o = 0 and it is the linear charge every earlier table on this site used. Set o=8o = 8 and e=1e = 1 and a gap of four costs 12 where four separate gaps of one cost 36.

That looks like a change to one constant. It is a change to what a cell has to know.

Why one table cannot do it

Consider a cell (i,j)(i, j) reached by putting a gap character in the lower string — stepping down from (i1,j)(i-1, j). What does that step cost?

If the step into (i1,j)(i-1, j) was also a downward step, the gap is already open and this character costs ee. If it was a diagonal step, the gap starts here and the character costs o+eo + e.

So the price of the step depends on how its predecessor was reached, and the cell at (i1,j)(i-1, j) holds a number. It holds the cheapest way to get there, and the cheapest way to get there may well be a route that leaves the gap closed, at a total that is lower by less than oo. A single-table recurrence has no way to ask the question and no way to pay for the answer.

The repair is to stop asking a cell for one number. Keep three:

  • M(i,j)M(i,j) — the cheapest way to reach (i,j)(i,j) having just aligned two characters;
  • D(i,j)D(i,j) — the cheapest way, having just extended a gap downwards;
  • I(i,j)I(i,j) — the cheapest way, having just extended one rightwards.

Write B(i,j)B(i,j) for the cheapest way to reach a cell by any of the three routes — the minimum of the three tables there. Then

M(i,j)=B(i1,j1)+s(ai,bj)D(i,j)=min{M(i1,j)+o+e,  D(i1,j)+e}I(i,j)=min{M(i,j1)+o+e,  I(i,j1)+e}\begin{aligned} M(i,j) &= B(i-1,\,j-1) + s(a_i, b_j) \\ D(i,j) &= \min\{M(i-1,j) + o + e,\; D(i-1,j) + e\} \\ I(i,j) &= \min\{M(i,j-1) + o + e,\; I(i,j-1) + e\} \end{aligned}

Read the second line: opening a gap from a matched state costs o+eo + e; continuing one from a gap state costs ee. The third coordinate — which of the three — is exactly the fact a single number could not carry.

unit cost, affine gaps (8 + 1·k): 19 costEach cell holds the cheapest of three ways to reach it: having just aligned two characters, having just extended a gap downwards, or having just extended one rightwards. Those are three separate tables and all three were filled — 495 cells across three tables, 980 transitions — because the price of a gap character depends on whether the step before it was already inside a gap, and a cell holding one number has thrown that away.agcacacggatcagccagggagta09101112131415161718192021229110101212141416171819192122101021011121314151718191920221110113101212141516171920192112121012411131314151718202119131312111351214131416181921211414131312146131413151719202115141514131314714151316181921161614161514141571416141719191717171517161515168151615182018171818151816161617816171519one unit = one subproblem given a value495 cells across three tables, 980 transitions
Fig. 1 The three tables read as one: each cell shows the cheapest of the three routes into it. That number is what a single-table version would try to hold, and holding only it is what makes the single-table version wrong — the two numbers it discards are the ones the next row needs.

What it costs, exactly

Three tables over the same rectangle, so three times the cells:

cells transitions transitions per interior cell
one table, linear gaps 165 420 3
three tables, affine gaps 495 980 7

Seven rather than three, because MM takes a minimum over three predecessors and DD and II take a minimum over two each.

Neither number changes the exponent. Both are Θ(nm)\Theta(nm), both grow the same way, and a statement that affine gaps are asymptotically free is correct.

Three times the memory is not free on a real problem. Aligning two sequences of thirty thousand characters is nine hundred million cells at one table and 2.7 billion at three, and the difference between those two numbers is the difference between a machine that can do it and one that cannot. Which is why the linear-space methods matter more here than they did with one table, and why they carry over: a rolling frontier keeps three rows instead of one, and the divide-and-conquer construction keeps three lines instead of one.

The version everybody writes first

There is a shortcut, it is the natural thing to try, and it is worth taking seriously because it is not a bug. Charge every gap character o+eo + e in a single table:

D(i,j)=D(i1,j)+(o+e)D(i,j) = D(i-1,j) + (o + e)

This is a valid cost model. It is simply a different one — a linear charge at a higher rate, in which a gap of four costs four times what a gap of one costs. On any pair whose gaps are all of length one it agrees with the affine model exactly, which is why it survives casual testing.

On a pair with a real gap it does not agree, and it goes wrong in two ways at once.

A gap of 4 characters, charged two waysThe same pair under an affine charge of 8 to open a gap and 1 for each character in it, computed twice. The upper alignment comes from three tables, which is the only way a cell can know whether the step above it was already inside a gap. The lower one comes from a single table charging 9 for every gap character, which is a valid cost model and a different one, and reports 39 where the affine cost is 19.three tables: 19 cost, 1 gap run(s), longest 4----ccagggagta|××||×××××agcacacggatcagone table charging 9 a character: 39 cost, 3 gap run(s)--c-cagggagta-|||×|||××|agcacacggatcag| identical x substituted - gap0,0,0,1,0,2,0,3,0,4,1,5,2,6,3,7,4,8,5,9,6,10,7,11,8,12,9,13,10,14 cells against 165
Fig. 2 The same pair under a charge of 8 to open and 1 per character, computed twice. Three tables put the whole gap in one run of four and report 19. One table charging 9 per gap character reports 39, and its alignment has three separate gap runs of at most two characters each.

The number is more than twice as large: 39 against 19. That much is expected — the flat charge is dearer per character by construction.

The shape is the part worth noticing. Under the flat charge every gap character costs 9 whatever its neighbours are doing, so nothing in the arithmetic prefers one run of four to three runs of one and two. The optimum is genuinely degenerate between them, the tie-break decides, and what comes out is a scattered alignment. Under the affine charge one run of four costs 12 and three runs costing 8+k8 + k each cost 28, so the arithmetic prefers the single run and there is nothing for a tie-break to decide.

That is the practical difference. The wrong version does not merely mis-price an alignment; it stops preferring the alignment the model was introduced to prefer.

Edit distance between ccagggagta and agcacacggatcag: 7Each cell holds the distance between a prefix of ccagggagta and a prefix of agcacacggatcag. The shaded run from the top left to the bottom right is one optimal alignment; where the table has ties there are others, and this one breaks them towards the diagonal. 165 cells, 165 held at once.agcacacggatcagccagggagta0123456789101112131411223456789101112132222334567891011123233233456789101143233344456789105433444544567896544455554567887655455665456788766556666556779877666777656781098877678876667one unit = one subproblem given a value165 cells, 165 held at once
Fig. 3 And the same pair under plain unit cost, which fragments in exactly the same way and for exactly the same reason: three gap runs, none longer than two. Affine gaps were introduced to stop this, and a single table charging a flat premium does not.

This site’s gate carries the discrepancy as a rejection rather than as a measurement. A run charging every gap character the opening price must report a total above the affine one and an alignment with more gap runs, or the check has stopped working.

The infinities are load-bearing

Three tables need three sets of boundary values, and two of the three are unreachable states rather than cheap ones.

M(0,j)M(0,j) asks the cost of reaching column jj of the top row having just aligned two characters — and no characters have been aligned. It is not zero. It is not jej \cdot e. It is impossible, and it has to be represented as something no minimum will ever choose.

This matters more than it sounds. The tables field’s own rule is that a cell which has not been computed must be distinguishable from a cell holding zero, because a zero absorbed into a minimum produces a smooth wrong curve rather than a crash. The same failure is available here one level up: initialise M(0,j)M(0,j) to zero and the table will cheerfully report that a gap costs nothing provided it starts at the beginning, and the answer will look plausible on every pair whose optimal alignment does not begin with a gap.

So the corner is read as B(m,n)B(m,n) — the cheapest of the three states the alignment could end in — and the three boundaries are three different statements about what is reachable.

The traceback has to know too

Recovering the alignment is where the three tables stop being an implementation detail.

A traceback over a single table asks, at each cell, which predecessor’s value plus the step cost equals this cell’s value. Over three tables the same question needs the third coordinate: from D(i,j)D(i,j) the predecessor is D(i1,j)D(i-1,j) if the gap was already open and M(i1,j)M(i-1,j) if it was not, and the two are distinguished by which of D(i1,j)+eD(i-1,j) + e and M(i1,j)+o+eM(i-1,j) + o + e achieved the minimum.

A traceback that consults only the cell-wise minimum gets this wrong in a specific and quiet way: it re-derives the gap opening cost at every step of a run, finds that the arithmetic does not close, and falls through to whichever branch its final else names. The alignment it returns is a legal alignment and its cost is not the number the table reported.

What the two parameters do

The opening price and the extension price are two numbers and their ratio is what matters — the same observation as the ratio between a substitution and a gap, one level along.

"ccagggagta" against "agcacacggatcag", priced four waysThe same two strings and the same rectangle of subproblems under four cost models. The bars are not comparable with each other and that is the point: the first is a count of edits, the third is a number of bits under a stated mutation model, and the fourth counts gap events and gap characters at different rates. Each is correct under its own rule and none of them is the distance between these strings.unit cost7editsunit cost, affine gaps (3 + 1·k)14costunit cost, affine gaps (8 + 1·k)19costtransition/transversion, affine gaps23costfour models, one pair of strings, four answers165 cells each
Fig. 4 The same pair under four rules, two of them affine. The gentler affine charge of 3 + k returns 14 with three optimal alignments; the steeper 8 + k returns 19 with one. Raising the opening price does not merely scale the answer, it removes the ties.

Swept properly, the opening price does its work in a narrow band and then stops:

oo answer gap runs longest run substitutions optimal alignments
0 7 3 2 3 2
1 10 2 3 4 3
2 12 2 3 4 2
3 14 1 4 7 3
4 15 1 4 7 1
8 19 1 4 7 1
20 31 1 4 7 1

Three things are visible in that table and only one of them is obvious.

The obvious one is that the answer climbs — of course it does, the gaps are getting dearer.

The second is that the number of gap characters never moves. It is four at every setting, and it has to be: these strings differ in length by four, so four gap characters are forced by arithmetic and no cost model can avoid them. What the opening price buys is not fewer gap characters but fewer runs of them, and it buys the last of that by o=3o = 3.

The third is that beyond o=4o = 4 nothing changes at all except the total. The alignment is frozen, the ties are gone, and every further increase is a scale factor on a decision that has already been made. A parameter sweep that reported only the answer would show a straight line climbing forever and would show none of this.

At o=0o = 0 the three tables collapse: DD and II become MM plus a constant per step and the whole construction is the ordinary one doing three times the work for nothing. At oo very large, gaps stop being used at all and the alignment becomes a straight diagonal with substitutions everywhere — the same degenerate edge the substitution-against-gap ratio has, reached from the other side.

Between the two there is a range in which the model is doing what it was introduced to do, and where that range sits depends on the substitution costs, because a gap competes against a substitution and not against nothing.

unit cost, affine gaps (8 + 1·k): 3 costEach cell holds the cheapest of three ways to reach it: having just aligned two characters, having just extended a gap downwards, or having just extended one rightwards. Those are three separate tables and all three were filled — 300 cells across three tables, 567 transitions — because the price of a gap character depends on whether the step before it was already inside a gap, and a cell holding one number has thrown that away.gactacgatgattacagt091011121314151617909101112131415161090910111213141511109191112131414121110101101112131413121111101101112131413121111101101112151413131211102101216151414131211103111716151514131212113one unit = one subproblem given a value300 cells across three tables, 567 transitions
Fig. 5 A third pair, at the same gap charge. Every cell prints the best of three and the caption prints all three tables’ cells, which is the family’s own rule: a plate that reported the rectangle rather than the three would understate the work by a factor of three and would be reporting a table that was never filled.

Three tables, one set of rules about reading them

The ordering discipline the tables field enforces — a cell may be written once, may not be read before it is written, and raises a different error when it is read after being released — applies across all three tables here, and it catches one thing it could not catch with one.

M(i,j)M(i,j) reads three cells at (i1,j1)(i-1,j-1), one from each table. D(i,j)D(i,j) reads two at (i1,j)(i-1,j). I(i,j)I(i,j) reads two at (i,j1)(i,j-1). Fill the three tables in the wrong interleaving — all of MM, then all of DD, then all of II — and every one of those reads is a read of a cell that has not been written yet, and the discipline says so at the first one.

Against three zero-filled arrays it would say nothing. It would report a smaller answer, because a zero absorbed into a minimum is always an improvement, and the answer would be smaller by an amount that depends on the strings. That is the exact failure mode the tables field was built around, and having three tables instead of one multiplies the number of ways to arrive at it rather than reducing them.

The opening charge is a parameter, and moving it moves the answer without moving anything about the machinery. Charge 3 to open rather than 8, on the same pair and through the same three tables: the cells and the transitions are the same numbers, because the shape of the computation is set by the rectangle rather than by the prices in it.

unit cost, affine gaps (3 + 1·k): 14 costEach cell holds the cheapest of three ways to reach it: having just aligned two characters, having just extended a gap downwards, or having just extended one rightwards. Those are three separate tables and all three were filled — 495 cells across three tables, 980 transitions — because the price of a gap character depends on whether the step before it was already inside a gap, and a cell holding one number has thrown that away.agcacacggatcagccagggagta04567891011121314151617415577991112131414161755256789101213141415176563577910111214151416775746889101213151614887685798911131416169988796898101214151610910988979108111314151111911109910791191214141212121012111010118101110131513121313101311111112811121014one unit = one subproblem given a value495 cells across three tables, 980 transitions
Fig. 6 The first pair again at the gentler charge of 3 + 1·k rather than 8 + 1·k. The total falls from 19 to 14 and the traced alignment moves; the bill does not — 495 cells across three tables and 980 transitions at either price. A cost model is free and an extra table is not.
unit cost, affine gaps (8 + 1·k): 15 costEach cell holds the cheapest of three ways to reach it: having just aligned two characters, having just extended a gap downwards, or having just extended one rightwards. Those are three separate tables and all three were filled — 663 cells across three tables, 1344 transitions — because the price of a gap character depends on whether the step before it was already inside a gap, and a cell holding one number has thrown that away.acgtttttttttacgtacgtacgtacgt09101112131415161718192021222324909101112131415161718192021222310909101112131415161718192021221110909101112131415161718192021121110909101112131415161718192013121110911011121314151616181920141312111010211121314151617161920151413121111113121314151617181620161514131211111131213141516171816171615141313121212413141515171819181716151414141313135141516151819191817161515151514141461516171519201918171615151515141414615161715one unit = one subproblem given a value663 cells across three tables, 1344 transitions
Fig. 7 The constructed pair, whose eight-character insertion is the case the affine charge exists for. Both versions find the same shape here; the plate is in this essay because a pair like it is what a careless test uses, and a careless test passes.

The gaps at the ends are not events

There is a second thing an affine model is usually asked for and it is not in the recurrence above: the gaps at the two ends should be free.

The reason is the same reason the opening price exists. A short sequence compared against a long one — a read against a reference, a quotation against a document, a fragment against a whole — is not a shorter version of the long one with material deleted. It is a piece of it. The characters of the reference before and after the piece were never removed by any event; they are simply outside the comparison, and charging o+eko + e k for each end is charging for two events that did not happen.

The repair is a boundary condition rather than a fourth table, and it is exactly the manoeuvre zeroing the top row performs on the unit-cost table, done twice and in the right state. Let the leading gap be entered for nothing — initialise the appropriate gap table’s boundary to zero rather than to o+eko + ek — and read the answer as the best cell along the final row or column rather than at the corner, so the trailing gap is unpaid too.

Which boundary and which table is where this goes wrong, and the failure is the quiet kind.

Zeroing the gap state’s boundary is correct: it says a run of leading gap characters is free, and the alignment proper begins when the first characters are matched. Zeroing the matched state’s boundary instead says something quite different — that an alignment may restart at any column with no penalty — and since that boundary is the one an implementer reaches for first, by analogy with the unit-cost table where there is only one, the mistake is easy to make and produces a table that quietly answers the local-alignment question instead.

Both tables produce plausible numbers on a pair whose match is in the middle. They diverge on a pair with two separated similar regions, where the correct semi-global answer must choose one and the accidental local one stitches both together across a free gap. Three of these four things are one-line edits to a boundary and each of them names a different problem, which is the same finding the unit-cost table produced and is worth having twice, because with three tables there are three times as many boundaries to get wrong.

The number of tables is the model’s state count

Standing back from Gotoh’s construction, the shape of it is more general than the affine model and worth naming, because it says immediately what any new gap rule will cost.

The single-table recurrence assumes the price of a step depends only on where the step goes. The affine rule breaks that: a step’s price depends on what the previous step was. So the alignment is not a path through a grid any more — it is a path through a grid crossed with a small automaton, whose states are matched, in a downward gap and in a rightward gap, and whose transitions carry the prices. Three states, three tables, and the recurrence above is that automaton written out.

Read that way, three things follow without any further argument.

The cell count is the grid times the state count. Three states, three times the cells; and the transition count per cell is the automaton’s in-degree, which is why it is seven rather than three. Nothing about this is specific to gaps.

A richer gap rule costs states, not classes. Modern aligners use a two-piece rule — one affine charge for short gaps and a second, cheaper-per-character one for long ones — because a single line does not fit both a three-character indel and a ten-thousand-character structural variant. That is five states rather than three, so five tables, and every property in this essay carries over unchanged with a five in place of a three. The class is untouched, the constant is nearly doubled, and the alignment stops fragmenting a second kind of gap.

And a general gap function has an unbounded state count, which is exactly why it does not fit. Knowing how much a step costs requires knowing how long the current run is, the run can be as long as the string, and an automaton with nn states over a grid of nmnm cells is the Θ(nm(n+m))\Theta(nm(n+m)) the next section names. The concave and convex methods escape not by shrinking the automaton but by refusing to enumerate its states, which is a different kind of move and is why they need their own machinery.

The transferable rule is compact enough to carry to any recurrence at all: a dynamic program’s table count is the number of things a cell must remember besides where it is, and the moment a cost depends on how a cell was reached, that number is at least two.

Where affine stops

Affine is not the general case. It is the largest family of gap costs that fits in a constant number of tables, and that is why it is the one everybody uses.

A general gap function γ(k)\gamma(k) — anything that is not o+eko + ek — brings back the problem the three tables solved, because a cell would need to know not merely whether it is inside a gap but how long the gap has been going. Written naively that is a minimum over all kk at every cell, which turns Θ(nm)\Theta(nm) into Θ(nm(n+m))\Theta(nm(n+m)): on two strings of three hundred characters, about twenty-seven million transitions instead of a hundred and eighty thousand.

There are better methods for the concave and convex cases, which exploit the shape of γ\gamma to keep a candidate list per row rather than reconsidering every kk. They are real, they are not implemented here, and quoting their bounds beside measured numbers would be mixing two kinds of statement — so this is a boundary of what this collection has measured rather than a boundary of what is known.

What is measured is the shape of the trade at the point everybody sits on: three times the cells, seven transitions instead of three per cell, no change to the class, and an alignment that stops fragmenting. The first three are prices and the last is the reason to pay them.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

What links here

The 8 essays that link to this one and share the most of its objects, of 10 that link here.

The objects this essay names

Each one links to every other essay that touches it.

Affine gapAlignmentCost modelDynamic programmingHonest limitMeasurementStateSubproblemTracebackTrade offUnit of cost