Computation

A code that survives a lost bit

A flipped bit leaves the word the right length and wrong in one place; a lost bit leaves it one short, with no sign of where the gap was. Keep only the words whose 1s sit at positions adding up to a multiple of n + 1, and any single lost bit can be put back. The price is about log₂(n + 1) bits, the same as the Hamming code pays for a flip.

Worth reading first: Finding the error without reading the message · The best a code can be.

Every code met so far has been built against one kind of damage: a symbol that arrives wrong. Distance is a picture drew a message as a corner of a cube and an error as a step to a neighbouring corner; finding the error without reading the message located a single wrong bit by the Hamming code’s syndrome; erasures a code can see handled symbols known to be missing, at known places. All of them assume the word arrives at its proper length, so that bit five of what was received is bit five of what was sent.

Reed–Solomon codes, which a polynomial through the gaps built, make the same assumption. A different and nastier failure breaks it. A bit is not changed but lost — a clock slips, a reader skips a mark, a molecule in a DNA strand is not copied — and the received word is one bit short, with every bit after the gap shifted one place left and nothing to show where the gap was. Against this, a substitution-correcting code is useless: a lost bit near the start changes almost every position of the received word, which is far from every codeword. This essay is about the family of codes that answers it, found by Rom Varshamov and Grigory Tenengolts in 1965 for a different purpose, and shown by Vladimir Levenshtein the same year to correct a single lost bit or a single inserted one.

A word that survives losing any one of its bits. codeword 100110010110, a=0 mod 13; deletions at 1..12 all decoded.
Fig. 1 A 12-bit codeword whose weighted sum is a multiple of 13, with each of its bits lost in turn. Every row is the 11 bits received; the bit the decoder puts back is shown blue, and every repair gives back the codeword.

One congruence on the positions of the ones

Number the bits of a word x1x2…xnx_1 x_2 \ldots x_n from the left, and add up the positions that hold a 1: the weighted sum ∑i xi\sum i\,x_i. The Varshamov–Tenengolts code VTa(n)\mathrm{VT}_a(n) is every word of length nn whose weighted sum leaves remainder aa on division by n+1n + 1. The first figure’s codeword is 100110010110100110010110, with ones at positions 1, 4, 5, 8, 10 and 11, adding to 39, which is three times 13. It belongs to VT0(12)\mathrm{VT}_0(12).

That is the whole definition, and it is not obvious that it should do anything. The Hamming code, by contrast, is a carefully designed linear subspace whose parity checks are the binary digits of the positions; here there is one congruence on one number. Its power comes from a fact about what a deletion does to the weighted sum. Suppose a bit is lost, and suppose ww ones and some number of zeros lie to its right. Every bit to the right moves one place left, so each of the ones there loses one from its position, and the weighted sum falls by wrightw_\text{right}, the number of ones to the right. If the lost bit was itself a 1 at position pp, the sum falls by pp as well. Either way the receiver can compute the shortfall DD — the remainder aa minus the weighted sum of what arrived, modulo n+1n + 1 — and that shortfall is a number between 0 and nn that encodes where the bit went.

Levenshtein’s rule for putting it back

Levenshtein’s decoder reads two numbers off the received n−1n - 1 bits: the number of ones ww and the shortfall DD. The rule is then mechanical:

  • if D≤wD \le w, a 0 was lost, and it goes back in at a place with exactly DD ones to its right;
  • if D>wD > w, a 1 was lost, and it goes back in at a place with exactly D−w−1D - w - 1 zeros to its left.

The first case is the arithmetic above: a lost 0 costs the sum nothing itself, only the DD ones to its right that shifted. In the second case a lost 1 at position pp costs pp plus the ones to its right, and pp equals one more than the zeros to its left plus the ones to its left; adding the ones on both sides gives ww, so the shortfall is w+1w + 1 plus the zeros to the left, which is why the count is D−w−1D - w - 1.

The hero runs the rule on all twelve deletions. Losing bit 1, a 1 with five ones after it, leaves D=6>5D = 6 > 5, so a 1 goes back with no zeros before it: the front. Losing bit 9, a 0, leaves D=2≤6D = 2 \le 6, so a 0 goes back with two ones to its right. The repair is not always at the position the bit came from. Losing bit 2 or bit 3, both 0s in the run 0000, gives the same received word, and the decoder puts a 0 back somewhere in that run; the result is the same codeword either way, because removing any bit of a run of equal bits gives the same string. A decoder for deletions does not need to know which bit was lost, only what the word was.

Every codeword, every deletion

Every codeword, every deletion, decoded. n=4: 4 words, 16 deletions, 0 wrong; n=5: 6 words, 30 deletions, 0 wrong; n=6: 10 words, 60 deletions, 0 wrong; n=7: 16 words, 112 deletions, 0 wrong; n=8: 30 words, 240 deletions, 0 wrong; n=9: 52 words, 468 deletions, 0 wrong; n=10: 94 words, 940 deletions, 0 wrong; n=11: 172 words, 1892 deletions, 0 wrong; n=12: 316 words, 3792 deletions, 0 wrong; n=13: 586 words, 7618 deletions, 0 wrong; n=14: 1096 words, 15344 deletions, 0 wrong; n=15: 2048 words, 30720 deletions, 0 wrong; n=16: 3856 words, 61696 deletions, 0 wrong
Fig. 2 For every length from 4 to 16, every codeword of VT0(n)\mathrm{VT}_0(n) with every bit deleted in turn and decoded, none wrongly; the redundancy stays near log⁡2(n+1)\log_2(n + 1).

A rule derived in a paragraph should be tested exhaustively, and at these lengths it can be. For each nn from 4 to 16 the figure lists every word of VT0(n)\mathrm{VT}_0(n), deletes each of its nn bits in turn, decodes, and compares — 61,696 deletions at n=16n = 16 alone, from 3,856 codewords — and not one is decoded wrongly. A second, independent check confirms the property the decoder relies on: for every nn up to 12, no word of length n−1n - 1 can be reached by one deletion from two different codewords, so the received word always determines the codeword uniquely, whatever decoder is used.

The last column is the cost. A code with ∣C∣|C| words of length nn carries log⁡2∣C∣\log_2|C| bits of message, and the rest, n−log⁡2∣C∣n - \log_2|C|, is redundancy. For VT0(n)\mathrm{VT}_0(n) it is 2.00 bits at length 4, 3.00 at 7, 4.09 at 16 — always close to log⁡2(n+1)\log_2(n + 1), which is exactly the redundancy of the Hamming code of length nn, the best possible for correcting one substituted bit. Correcting a lost bit, whose position the received word does not even reveal, costs no more than correcting a flipped one. Levenshtein proved that this is the right order: no code correcting one deletion can have redundancy less than about log⁡2n\log_2 n.

The Hamming syndrome, added instead of combined

The congruence has a twin that the earlier essays already met. The Hamming code of length n=2m−1n = 2^m - 1 is also defined by the positions of a word’s ones: write each position ii in binary, as a string of mm bits, and combine the positions of the ones by adding their binary digits without carrying — the exclusive or. The result is the syndrome, and finding the error without reading the message showed that the codewords are exactly the words whose syndrome is zero, and that a single flipped bit at position pp changes the syndrome by exactly pp, which is how the decoder finds it.

The Varshamov–Tenengolts code is the same recipe with ordinary arithmetic. Combine the positions of the ones by adding them with carrying, modulo n+1n + 1, and keep the words whose total is zero. A flip at position pp would change this sum by ±p\pm p as well — so the same set of words also corrects a single flip that changes a 0 to a 1 or a 1 to a 0, when the receiver knows which direction is possible, which is the asymmetric problem Varshamov and Tenengolts were solving. But ordinary addition has a property the exclusive or lacks: it respects order. Shifting every bit after a gap one place to the left subtracts a predictable amount from an ordinary sum, the number of ones that moved, and the exclusive or of shifted positions has no such regularity at all. That one property, the compatibility of the sum with sliding, is what makes the construction correct deletions, and it is why the Hamming code, built on carry-less addition over the field of two elements, cannot.

So two of the most useful codes for single errors are one formula, ∑i xi\sum i\,x_i, evaluated in two different number systems. In the field of 2m2^m elements it corrects a substitution and nothing else; in the integers modulo n+1n + 1 it corrects a deletion, an insertion, or a one-directional flip. The redundancy is log⁡2(n+1)\log_2(n + 1) in both, because both store one number between 0 and nn — the size of the syndrome — and that number is all that either decoder needs.

How many words one deletion can reach

A deleted bit can leave as many words as there are runs. n=12: words by ball size 1:2, 2:22, 3:110, 4:330, 5:660, 6:924, 7:924, 8:660, 9:330, 10:110, 11:22, 12:2; mean 6.500.
Fig. 3 The 4,096 words of 12 bits sorted by how many different 11-bit words one deletion can turn them into — always exactly their number of runs of equal bits.

Codes for substitutions are understood through balls: around each codeword, the words one flip away, nn of them, and a code works if the balls do not overlap. The best a code can be turned that into the Hamming bound, 2n/(n+1)2^n/(n + 1) codewords at most. Deletions have balls too — around each word, the shorter words one deletion can produce — but the balls are not all the same size.

The figure counts them for every word of 12 bits. Deleting a bit inside a run of equal bits gives the same result wherever in the run the deletion happens, so the number of distinct results is exactly the number of runs. The word 000000000000000000000000 has one run and one result. The word 010101010101010101010101 has twelve runs and twelve results. A random word has about half its positions at the start of a new run, so the average is 6.5 — the bell in the figure, which is the binomial distribution of the number of places where adjacent bits differ.

The unequal balls change the counting argument. A code may hold more words where the balls are small, among the words with few runs, so the sphere-packing estimate is not a bound in the same way, and Levenshtein’s asymptotic answer — the largest code correcting one deletion has about 2n/n2^n/n words — comes from a more careful argument that weights each word by its run count. The ball of a word with few runs is small because deletions inside long runs are indistinguishable, which is the same reason the decoder could not and did not need to tell bits 2 and 3 apart.

Fifteen codes for the price of one

Fifteen codes that share out every word. n=14: |VTₐ| = 1096, 1091, 1091, 1094, 1091, 1092, 1094, 1091, 1091, 1094, 1092, 1091, 1094, 1091, 1091; Ginzburg's formula matches for lengths 4-16.
Fig. 4 The 16,384 words of 14 bits split into the 15 codes VTa(14)\mathrm{VT}_a(14) by the remainder of their weighted sum modulo 15. Each corrects one deletion; a=0a = 0 is the largest, with 1,096 words.

The residue aa was arbitrary, and every choice works: the decoder only needs to know which aa the sender used. So the 2n2^n words of length nn fall into n+1n + 1 codes, each correcting a single deletion, and they share out the words almost evenly. The figure draws the fifteen codes of length 14. The largest is VT0(14)\mathrm{VT}_0(14) with 1,096 words, the others have between 1,091 and 1,094, and 214/15≈1092.32^{14}/15 \approx 1092.3 is the average.

The sizes are not arbitrary either. Counting the words whose weighted sum has a given remainder is counting subsets of {1,…,n}\{1, \ldots, n\} with a given sum modulo n+1n + 1, and it has an exact answer, found by Ginzburg in 1967: a sum over the odd divisors of n+1n + 1 of Euler’s φ\varphi, the Möbius function and a power of two. Every count in the figure, and every count for every length from 4 to 16 and every aa, equals that divisor sum. It has precisely the shape of the formula that counts necklaces — binary strings up to rotation — which every necklace in order used to list Lyndon words. The resemblance is not a coincidence: rotating a subset of Z/(n+1)\mathbb{Z}/(n+1) shifts its sum by a multiple of its size, so the codes and the necklaces are two ways of grouping the same subsets. A code against lost bits turns out to be a question about how n+1n + 1 factors.

Nothing larger exists, at these lengths

No code corrects a deletion with more words. n=2: best 2, VT0 2 (1 nodes); n=3: best 2, VT0 2 (1 nodes); n=4: best 4, VT0 4 (1 nodes); n=5: best 6, VT0 6 (5 nodes); n=6: best 10, VT0 10 (62 nodes); n=7: best 16, VT0 16 (110766 nodes)
Fig. 5 For each length from 2 to 7, the largest set of words no two of which can be turned into the same word by one deletion, found by exhaustive search, against the size of VT0(n)\mathrm{VT}_0(n). They are equal at every length.

A code defined by one congruence ought to be beaten by something cleverer. The figure looks for something cleverer by brute force: among all 2n2^n words of length nn, the largest set in which no two words share a word one deletion away. That is a maximum independent set in a graph of 2n2^n vertices, and branch and bound finds it for every length up to 7. The answers are 2, 2, 4, 6, 10 and 16 — exactly the sizes of VT0(n)\mathrm{VT}_0(n) at every length. At these lengths, the one-line code is as large as any code that corrects a lost bit can be.

The search stops at 7 because the graph grows quickly; at length 8 it has 256 vertices and the bound that makes the search fast becomes weak. Neil Sloane, surveying these codes in 2002, recorded that searches by others had confirmed the same equality a few lengths further, and conjectured that it holds at every length. The conjecture is open: nobody has proved that VT0(n)\mathrm{VT}_0(n) is the largest single-deletion code for every nn, and nobody has found a length where it is not. The figure is a proof of the statement for n≤7n \le 7 and evidence beyond.

What one congruence cannot do

The congruence corrects one deletion, or one insertion — Levenshtein showed the two are equivalent, since a code that separates the deletion balls of its words also separates their insertion balls — and nothing more. Two lost bits defeat it completely. Codes correcting several deletions exist, and are much harder to build: for ss deletions the best known constructions use redundancy around c slog⁡nc\,s \log n for constants cc that have been coming down only recently, and the optimal constant is not known even for two. A substitution and a deletion together, or a burst of adjacent losses, need yet other designs.

The figures also say nothing about random deletions at a steady rate, which is how a real channel behaves. A channel that loses each bit independently with probability pp has a capacity — the best rate of reliable communication — and, unlike the erasure channel’s 1−p1 - p, nobody knows what it is. Upper and lower bounds have been proved and computed, and they do not meet for any pp strictly between 0 and 1. That the simplest synchronisation error has an unknown capacity, sixty years after Shannon computed the capacity of every memoryless channel, is because a deletion couples every position to every other, and the received sequence of a deletion channel is a random subsequence of what was sent — the object the longest thread between two random strings studied, whose own growth constants are unknown.

Still open: two lost bits

The cleanest open question is about two deletions. A congruence on ∑i xi\sum i\,x_i handles one; adding a congruence on ∑i2xi\sum i^2 x_i, or on sums over runs, handles two in several published constructions, with redundancy about 4log⁡2n4\log_2 n or better. The lower bound for two deletions is about 2log⁡2n2\log_2 n. Whether the factor of two can be closed — whether two deletions can be corrected as cheaply, relative to one, as several substitutions can be by the cyclic codes of the BCH family and their relative built from an icosahedron — is not known, and the constructions that come closest are recent and intricate.

For a single deletion the remaining question is the one Sloane posed. VT0(n)\mathrm{VT}_0(n) is optimal at every length anyone has checked and has never been beaten. A proof would need a way of showing that a deletion code cannot be enlarged that works at every length at once — an argument from the structure of deletion balls, which vary in size, rather than from a count of them — and no such argument is known.

A sum that remembers where the gap was

Keep the words of length nn whose ones sit at positions adding up to a multiple of n+1n + 1, and any single lost bit can be put back: the number of ones received and the shortfall in the weighted sum say whether a 0 or a 1 went, and where. Every codeword up to length 16 survives every deletion, and the redundancy is about log⁡2(n+1)\log_2(n + 1), the same as the Hamming code pays for a flipped bit. One deletion can leave only as many words as a word has runs, so these balls vary in size where Hamming balls do not; the n+1n + 1 codes share out all the words, with sizes given by a divisor sum shaped like the necklace count; and no larger code correcting one deletion exists at any length up to seven, though whether that holds at every length is still unproved.

Shares its objects with

Essays that name at least two of the same things, and that neither author linked.

Named objects

A dashed tag is an object no other essay names yet.

Error-correcting codeExhaustive searchHamming codeModular arithmeticNecklaceRedundancy