Kolmogorov Complexity
The Information in One Object

Shannon measures the information of a source. Kolmogorov measures the information of a single string: the length of its shortest program.

Definition

K(x) = shortest program for x. The invariance theorem makes it well-defined.

Limits

Most strings cannot be compressed. K itself cannot be computed.

Randomness

Random = incompressible. Martin-Löf, Chaitin's Ω, incompleteness.

Practice

MDL, Solomonoff induction, and NCD clustering with plain zlib and lzma.

Every Python snippet in this deck runs as shown. All outputs are copied from real runs with Python 3.11+ (standard library only).

Roadmap WHERE WE GO

  1. History: Solomonoff, Kolmogorov, Chaitin
  2. The description-length idea, with worked examples
  3. Formal definition of K(x)
  4. Invariance theorem, with proof
  5. Basic bounds: K(x) ≤ |x| + c
  6. Counting: most strings are incompressible
  7. The incompressibility method, and a worked proof
  8. Uncomputability: the Berry paradox
  9. Link to the halting problem
  10. Check yourself 1
  11. Prefix-free K, Kraft, and Elias codes by hand
  12. The coding theorem
  13. Expected K ≈ Shannon entropy H
  14. Conditional K and symmetry of information
  15. Information distance, NCD demo, NCD by hand
  16. Martin-Löf randomness and deficiency
  17. Chaitin's Ω and incompleteness
  18. Check yourself 2
  19. MDL and Solomonoff induction
  20. Logical depth and sophistication
  21. Compression as a proxy for K
  22. Pitfalls, summary and glossary

Three people, one idea HISTORY

YearEvent
1948Shannon: entropy of a random source.
1960–64Ray Solomonoff: a universal prior for induction, built from program lengths.
1965Andrey Kolmogorov: "Three approaches to the quantitative definition of information".
1966–69Gregory Chaitin, then 18–19, finds the same idea on his own.
1966Per Martin-Löf defines random infinite sequences by tests.
1974–75Levin, Gács and Chaitin: prefix-free K, coding theorem, Ω.
1978Rissanen: Minimum Description Length (MDL).
1988Bennett: logical depth.
1993Li & Vitányi's textbook. It is still the standard reference.
2004–05Cilibrasi & Vitányi: NCD. Clustering by compression.

Many names

It is also called algorithmic information, algorithmic entropy, program-size complexity, or descriptive complexity. Some write C(x) for the plain version and K(x) for the prefix-free version. We do the same.

Kolmogorov's three approaches (1965)

  1. Combinatorial: pick one of N objects, so log N bits.
  2. Probabilistic: Shannon's entropy.
  3. Algorithmic: the length of the shortest program. This is the new one. It needs no probability at all.

Which string is random? INTUITION

Toss a fair coin 32 times. Each string below has the same probability, 2−32:

A: 01010101010101010101010101010101
B: 00000000000000000000000000000000
C: 10011101001011100010110111010010

Yet everyone says C "looks random" and A and B do not. Probability cannot explain this. Every single string is equally unlikely.

Kolmogorov's answer

A has a short description: "print 01 sixteen times". B does too. For C, the shortest description seems to be C itself. A string is random when it has no description much shorter than itself.

Descriptions as programs

prog = 'print("ab" * 50000)'
print(len(prog), "chars of program for", len(samples["'ab' repeated"]), "bytes of output")
19 chars of program for 100000 bytes of output
program p |p| = 19 chars universal machine U output x |x| = 100000 K(x) = length of the shortest such p

Python is a fine universal machine for intuition. The theory uses a fixed universal Turing machine instead. The invariance theorem says the choice barely matters.

Describing strings by hand WORKED EXAMPLES

A handy trick. To describe x, name a set S that holds it. Then give x's position (index) inside S.

cost ≈ K(S) + log2|S| bits

The set is the pattern. The index is the leftover noise. Here n = 1000, and c is a small fixed cost for the decoder.

String x (1000 bits)How we describe itAbout
000…0"n zeros", just give nlog 1000 ≈ 10 + c
0101…01"01 repeated 500 times"log 500 ≈ 9 + c
exactly 3 onesn, then which of C(1000,3) sets27.3 + O(log n)
exactly 100 onesn, 100, then index in C(1000,100)464.4 + O(log n)
first 1000 bits of √2a fixed √2 program, plus nc + 10
1000 fair coin flipsno pattern, so print it≈ 1000

Trace one row: 100 ones

  1. Say n = 1000 and k = 100. That takes O(log n) bits.
  2. List every 1000-bit string with 100 ones, in order. There are C(1000,100) of them.
  3. Give x's index in that list: log2 C(1000,100) = 464.4 bits.

Compare Shannon: 1000·H(0.1) = 469.0 bits. Same answer, up to O(log n). We will prove this link later (K vs H).

Common mistake

"√2 looks random, so its K is high." No. Its bits pass many statistical tests. But a short program prints them. K asks for any pattern at all, not just the ones a test looks for.

Check yourself

About how many bits for 0110 repeated 250 times?

Give the 4-bit block and the count 250. That is about 4 + log 250 ≈ 12 bits, plus c.

The formal definition DEFINITION

Plain complexity. Let M be a partial computable function from binary strings to binary strings (a "machine"). Then

CM(x) = min { |p| : M(p) = x }

with min ∅ = ∞. Here p is a description (program) of x.

Conditional complexity. Give the machine side information y for free:

CM(x | y) = min { |p| : M(p, y) = x }

So C(x) = C(x | ε), where ε is the empty string.

Universal machine U: for every machine M, some string ⟨M⟩ exists with U(⟨M⟩ p) = M(p) for all p.

Objects other than strings

Encode them as strings first. A number n is its binary form. A pair is a self-delimiting encoding of both parts. Then K(n), K(x, y) and K(graph) all make sense.

Examples (up to an additive constant)

xC(x) about
0n (n zeros)C(n) ≤ log n
0n with n = 22klog k, tiny
first n digits of πlog n
n fair coin flipsn, almost surely
x x (a copy)C(x)

Logs are base 2. "± c" or O(1) means a constant that depends on U but not on x.

The invariance theorem THEOREM

Theorem (Solomonoff, Kolmogorov, Chaitin). Let U be universal. For every machine M, a constant cM exists with

CU(x) ≤ CM(x) + cM   for all x.

So if U and V are both universal, |CU(x) − CV(x)| ≤ cUV.

Proof

  1. Take a shortest M-description p of x. So M(p) = x and |p| = CM(x).
  2. By universality, U(⟨M⟩ p) = M(p) = x.
  3. So CU(x) ≤ |⟨M⟩| + |p| = CM(x) + cM, with cM = |⟨M⟩|.
  4. For two universal machines, apply this in both directions. ∎

One detail: U must know where ⟨M⟩ ends and p starts. So the machine codes ⟨M⟩ are chosen prefix-free.

⟨M⟩ p interpreter for M fixed cost cₘ shortest M-program U runs it, outputs x

What it means

  • K is a property of x, not of the language. Changing languages costs only a constant. That constant is the "compiler" from one to the other.
  • We write K(x) with no subscript, and read all claims "up to O(1)".

The fine print

The constant can be large. For one short string, K depends a lot on the machine. The theory is about long strings and asymptotics.

Basic bounds PROPERTIES

Upper bound. A constant c exists with C(x) ≤ |x| + c for all x.

Proof. Let M be the identity machine, M(p) = p. Then CM(x) = |x|. Apply invariance. ∎ In Python terms: print("...x...").

Computable maps don't add information. For computable f:

C(f(x)) ≤ C(x) + cf

Proof. Run the shortest program for x, then apply f. ∎ Sorting, encrypting with a fixed key, or copying never adds more than a constant.

Numbers. C(n) ≤ log n + c. And C(n) ≥ log n for most n.

FactBound (± O(1))
copyC(x x) ≤ C(x)
reverse, complementC(xR) = C(x)
lengthC(0n) = C(n)
pairs (plain C)C(x, y) ≤ C(x) + C(y) + 2 log C(x)
pairs (prefix K)K(x, y) ≤ K(x) + K(y)
prefix vs plainC(x) ≤ K(x) ≤ C(x) + 2 log C(x)
prefix upperK(x) ≤ |x| + 2 log |x|

Why the log terms?

To glue two programs together, the machine must know where the first one ends. Writing its length costs about log bits, doubled to make it self-delimiting. Prefix-free K builds this in (see the Kraft slide).

C is not monotone in prefixes. A long string can be simpler than one of its prefixes. For example, 0n with n = 22k is simpler than most shorter runs of zeros.

Most strings are incompressible COUNTING

Theorem. For every n and c, fewer than 2n−c strings of length n have C(x) < n − c. So at least 2n(1 − 2−c) strings are c-incompressible.

Proof (pigeonhole)

  1. A description shorter than n − c bits is one of 1 + 2 + 4 + … + 2n−c−1 = 2n−c − 1 strings.
  2. Each description yields at most one output.
  3. So at most 2n−c − 1 strings get a short description. ∎

With c = 0: at least one string of every length has C(x) ≥ n. That string is truly incompressible.

def fraction_compressible(n, c):
    """Fraction of n-bit strings that have a description of < n - c bits."""
    programs = 2 ** (n - c) - 1          # all strings of length 0 .. n-c-1
    return programs / 2 ** n
for c in [1, 2, 8, 10, 20]:
    print(f"save more than {c:>2} bits: at most {fraction_compressible(64, c):.7f} of 64-bit strings")
save more than  1 bits: at most 0.5000000 of 64-bit strings
save more than  2 bits: at most 0.2500000 of 64-bit strings
save more than  8 bits: at most 0.0039062 of 64-bit strings
save more than 10 bits: at most 0.0009766 of 64-bit strings
save more than 20 bits: at most 0.0000010 of 64-bit strings

So every compressor must lose

No lossless compressor can shrink all files. If it shrinks some, it must grow others. Fewer than 1 file in 1000 can shrink by more than 10 bits. zip works only because real files are far from random.

The incompressibility method PROOF TECHNIQUE

Recipe. Pick an incompressible object. Assume the claim fails. Use the failure to describe the object in too few bits. Contradiction.

Theorem. There are infinitely many primes.

Proof. Suppose only p1, …, pk exist. Then every n = p1e1 … pkek. Each ei ≤ log n, so it fits in log log n bits. Then n is described by its k exponents:

C(n) ≤ 2k log log n + c

Now pick an incompressible n with C(n) ≥ log n. For large n, log n > 2k log log n + c. Contradiction. ∎

Where the method shines

  • Average-case lower bounds. Shellsort, Heapsort, and routing tables. A "typical" input is an incompressible one.
  • Formal languages. A clean proof that {0n1n} is not regular. A DFA's state after 0n would describe n in O(1) bits.
  • Combinatorics. Random graphs have no large cliques. Tournaments and Ramsey bounds.
  • Communication complexity and circuit lower bounds.

Why it works

It replaces "for a random input, with high probability" with "for this incompressible input, always". One fixed object has every typical property at once. The counting slide says such objects exist.

Worked proof: 0n1n is not regular METHOD IN ACTION

Claim. No DFA accepts L = { 0n1n : n ≥ 0 }.

Proof, step by step.

  1. Assume a DFA A with q states accepts L. Its size is a constant.
  2. Pick a large n that is incompressible: C(n) ≥ log n. Counting says one exists.
  3. Run A on 0n. It stops in some state s. Naming s costs log q bits, still a constant.
  4. Rebuild n. From state s, the only m with 1m accepted is m = n. So "try m = 0, 1, 2, … from s" finds n.
  5. Count. That gives C(n) ≤ |A| + log q + c, a constant. But C(n) ≥ log n grows. Contradiction for large n. ∎

The idea in one line: a DFA's memory is a constant number of bits. The language needs it to remember a number that is not a constant.

Common mistakes

  • Picking a nice n, like n = 2k. It has a short description, so no contradiction appears. Pick an incompressible one.
  • Forgetting uniqueness. Step 4 only works if n is the only number that fits. Always say why the object is pinned down.
  • Counting A as input. A is fixed before n is chosen. Its size is O(1).

Check yourself

Show { ww : w ∈ {0,1}* } is not regular.

Take a DFA A for it. Pick x of length n with C(x) ≥ n. Run A on x and note the state s. From s, the only length-n string y that gets accepted is y = x. So A, s and n rebuild x: C(x) ≤ 2 log n + c. That is less than n for large n. Contradiction.

Compare the pumping lemma. It proves the same thing, but you must juggle "for all splits". The incompressibility proof has no case analysis.

K is uncomputable: the Berry paradox THEOREM

The Berry paradox (1906)

"The smallest number not definable in under sixty letters." That phrase has only 48 letters. So it defines the number in under sixty. Contradiction.

Theorem (Kolmogorov, Chaitin). No program computes K(x) for all x. Even any computable lower bound is bounded by a constant.

Proof

  1. Suppose program Kc computes K.
  2. Write Berry(L): "try strings in order, return the first x with Kc(x) > L". One exists, by counting.
  3. Its size is |Kc| + log L + c. So the output x has K(x) ≤ log L + c′.
  4. But K(x) > L by choice. For large L, L > log L + c′. Contradiction. ∎

With a computable proxy, the search is fine

from itertools import product
def first_hard(k):
    """First bit-string (by length, then lexicographic) whose zlib size is >= k bytes."""
    for n in range(1, 64):
        for bits in product(b"01", repeat=n):
            s = bytes(bits)
            if len(zlib.compress(s, 9)) >= k:
                return s
print(first_hard(20).decode())
00001011100110

This is no paradox. The program above is short, and it describes its output. That just proves zlib size is not K. zlib calls a 14-character bit string "20 bytes complex".

What is possible

K is upper semi-computable. Run all programs in parallel (dovetailing). Each time one outputs x, lower your estimate. The estimates reach K(x) at some point. But you can never know when.

K and the halting problem SAME DIFFICULTY

Theorem. Computing K and solving the halting problem are Turing-equivalent. Each one can be computed using the other as an oracle.

Halting ⇒ K

For L = 0, 1, 2, …: list every program of length L. Ask the oracle which ones halt. Run just those. The first L where some program outputs x is K(x).

K ⇒ Halting

Fix n and let m = n + c. Using K, list every string with K(x) < m (a finite set). Dovetail all programs until each of those strings has been printed. Call that time T. Suppose some program p with |p| < n halts at time t > T. Then "run p to learn t; run every program for t steps; print the first string of length m not yet printed" is a program of length n + O(1). Its output has K ≥ m = n + c. For large c that is a contradiction. So every halting program shorter than n halts by time T. Run them all for T steps and you know which ones halt.

K(x) oracle HALT oracle wait out the short strings run only halting programs

The lesson

  • Short programs that never halt are the core problem. You cannot rule them out, so you can never be sure you found the shortest one.
  • Every practical "K estimate" is really an upper bound: a compressor, a model, or a program you found.

Recap & check yourself (part 1) PRACTICE

What we have so far

  • K(x) is the length of the shortest program that prints x.
  • Changing the language costs only a constant (invariance).
  • K(x) ≤ |x| + c. Most strings come close to that.
  • Incompressible objects make short, clean proofs.
  • No program computes K. It is as hard as halting.

Common mistake

"K is uncomputable, so it is useless." No. We can't compute it, but we can prove things with it. And we can bound it from above with any compressor.

Try these first, then open the answers

  1. Can a compressor shrink every 1000-bit file by at least 1 bit?
    AnswerNo. There are 21000 files but only 21000 − 1 shorter strings. Two files would share an output (pigeonhole).
  2. Show that C(xx) ≤ C(x) + c.
    AnswerTake the shortest program for x. Wrap it: "run this, then print the result twice". The wrapper is a fixed size c.
  3. At most what fraction of 100-bit strings have C(x) < 90?
    AnswerThere are fewer than 290 programs shorter than 90 bits. So the fraction is below 290/2100 = 1/1024.
  4. A friend says their program computes K(x). Why must it be wrong?
    AnswerUse it to find the first x with K(x) > L. That search is only log L + c bits long, and it prints x. So K(x) ≤ log L + c, which is less than L. Berry's paradox.
  5. Why does "K(0110) = 3" mean nothing?
    AnswerK is only fixed up to the invariance constant. You can pick a machine where 0110 has a 1-bit program. K speaks about long strings and growth rates.

Prefix-free K and the Kraft inequality SELF-DELIMITING

Prefix-free set: no word is a proper prefix of another. A prefix machine has a prefix-free domain. Then a program "knows where it ends", like a Huffman code.

K(x) = min { |p| : Uprefix(p) = x }

Kraft inequality. If S is prefix-free, then ∑w∈S 2−|w| ≤ 1. Conversely, any lengths with this sum ≤ 1 can be realized by some prefix-free code.

Proof. Word w owns the interval [0.w, 0.w + 2−|w|) in [0,1). Prefix-free means these intervals don't overlap. So their total length is at most 1. ∎

Why bother?

  • K(x, y) ≤ K(x) + K(y) + O(1), with no log term.
  • ∑x 2−K(x) ≤ 1. So 2−K(x) acts like a probability. This gives Ω and the coding theorem.
def elias_gamma(n: int) -> str:
    b = bin(n)[2:]
    return "0" * (len(b) - 1) + b

def elias_delta(n: int) -> str:
    b = bin(n)[2:]
    return elias_gamma(len(b)) + b[1:]

for n in [1, 2, 5, 17, 1000]:
    print(f"{n:>5}  gamma={elias_gamma(n):<20} delta={elias_delta(n)}")

codes = [elias_gamma(n) for n in range(1, 2000)]
print("prefix-free:", is_prefix_free(codes),
      " Kraft sum:", round(sum(2 ** -len(w) for w in codes), 6))
    1  gamma=1                    delta=1
    2  gamma=010                  delta=0100
    5  gamma=00101                delta=01101
   17  gamma=000010001            delta=001010001
 1000  gamma=0000000001111101000  delta=0001010111101000
prefix-free: True  Kraft sum: 0.999489

Gamma costs 2 log n + 1 bits. Delta costs log n + 2 log log n + O(1). is_prefix_free sorts the words and checks neighbours. The Kraft sum tends to 1 as more words are added.

Prefix codes by hand: Elias gamma and delta WORKED EXAMPLE

Gamma: say the length in unary, then the number

Write n in binary. If it has L bits, put L − 1 zeros in front.

nbinarygamma(n)2−len
1111/2
2, 310, 11010, 0111/8 each
4–7100–11100100 … 001111/32 each
13110100011011/128

Kraft sum for 1..7: 1/2 + 2/8 + 4/32 = 0.875 ≤ 1. Good.

Delta: say the length in gamma

13 = 1101 has 4 bits. So write gamma(4) = 00100, then the bits after the leading 1: 101. Result 00100101 (8 bits). Gamma used 7 here, but delta wins for large n.

Decode a stream: 001010100111

  1. Two zeros, so read the next 3 bits: 101 = 5.
  2. One zero, so read 2 bits: 10 = 2.
  3. One zero, so read 2 bits: 11 = 3.
  4. No zeros, so read 1 bit: 1 = 1.

No commas needed. Each word tells you where it ends. That is what "prefix-free" buys.

Common mistakes

  • Kraft goes one way for a given code. {0, 01, 11} has sum 1/2+1/4+1/4 = 1. But 0 is a prefix of 01, so it is not prefix-free. The theorem only says some code with lengths 1, 2, 2 exists: {0, 10, 11}.
  • Lengths {1, 1, 2} sum to 1.25 > 1. No prefix code has them. Don't try.

Check yourself

What is gamma(9), and how long is it?

9 = 1001, 4 bits. So gamma(9) = 0001001, 7 bits = 2⌊log 9⌋ + 1.

The universal distribution and the coding theorem LEVIN 1974

Algorithmic probability. Feed a prefix machine U fair coin flips. The chance it outputs x is

m(x) = ∑p : U(p) = x 2−|p|

Kraft gives ∑x m(x) ≤ 1, since some programs never halt. It is a semimeasure.

Coding theorem. K(x) = −log m(x) + O(1).

Sketch. The ≥ side holds because the shortest program alone adds 2−K(x) to m(x). For ≤, approximate m from below. Then use the Kraft–Chaitin construction to give each x a codeword of length −log m(x) + 2. That code is a prefix machine, so invariance applies.

Reading the theorem

  • The shortest program dominates the sum over all programs.
  • Simple objects are likely. Complex objects are unlikely. This is Occam's razor, made into a theorem.
  • m is universal. For every computable (or lower semi-computable) semimeasure P, m(x) ≥ 2−K(P) P(x). It "multiplicatively dominates" them all.
ShannonKolmogorov
code length −log P(x)K(x) = −log m(x)
needs to know Pone prior m for everything
Kraft for codesKraft for programs

Levin calls m the "a priori probability". Solomonoff used the same idea for prediction (see later).

Expected K ≈ Shannon entropy BRIDGE

Theorem. Let P be a computable distribution on strings. Then

0 ≤ ∑x P(x) K(x) − H(P) ≤ K(P) + O(1)

Proof sketch

  • Left: the programs {px} form a prefix-free code. Shannon's source coding theorem says no prefix code beats H on average.
  • Right: build a Shannon–Fano code for P, with lengths ⌈−log P(x)⌉. A program with ⟨P⟩ can decode it. So K(x) ≤ −log P(x) + K(P) + O(1). Take the average.

For n i.i.d. draws, divide by n. The K(P)/n term vanishes. Per symbol, expected K equals the entropy rate.

def H(p): return -p * math.log2(p) - (1 - p) * math.log2(1 - p)

print(f"{'p':>5}{'H(p)':>8}{'lzma bits/bit':>15}")
for p in [0.5, 0.25, 0.1, 0.01]:
    data = bernoulli_bytes(p, 400_000, seed=7)
    rate = 8 * len(lzma.compress(data, preset=9)) / 400_000
    print(f"{p:>5}{H(p):>8.3f}{rate:>15.3f}")
    p    H(p)  lzma bits/bit
  0.5   1.000          1.001
 0.25   0.811          0.838
  0.1   0.469          0.502
 0.01   0.081          0.107

bernoulli_bytes(p, n, seed) packs n biased coin flips into bytes. lzma is a general tool, not tuned for this source. It still lands within about 0.03 bits of the entropy.

But not per string

H describes the average. One sample 0n from a fair coin has K ≈ log n, far below n. K answers questions about single objects that H cannot.

Conditional K and symmetry of information MUTUAL INFO

Conditional K: K(x | y) is the shortest program that outputs x when given y. It measures how much new information x has beyond y.

Symmetry of information (Kolmogorov–Levin 1968, Gács 1974, Chaitin 1975).

K(x, y) = K(x) + K(y | x, K(x)) + O(1)

So the algorithmic mutual information

I(x : y) = K(y) − K(y | x*)

is symmetric: I(x : y) = I(y : x) + O(1). Here x* is the shortest program for x.

Compare Shannon: H(X,Y) = H(X) + H(Y|X). The algorithmic version is the same law, for single objects, with the small K(x) correction.

Estimate it with a compressor

def C_given(x: bytes, y: bytes) -> int:
    """C(x | y) ~ C(y + x) - C(y)."""
    return C(y + x) - C(y)
x = docs["dnaA'"]
print("C(x) =", C(x), "  C(x | dnaA) =", C_given(x, docs["dnaA"]),
      "  C(x | dnaB) =", C_given(x, docs["dnaB"]))
C(x) = 1178   C(x | dnaA) = 631   C(x | dnaB) = 1109
  • dnaA' is dnaA with 10% of its letters changed.
  • Knowing dnaA nearly halves the cost. What is left is mostly the mutations.
  • Knowing an unrelated dnaB barely helps.

C(x) is the smallest of zlib, lzma and bz2 output, in bytes. The docs are built on the NCD slide. The trick "compress y then x" is the idea behind NCD.

Information distance and NCD SIMILARITY

Information distance (Bennett, Gács, Li, Vitányi, Zurek 1998): the shortest program that turns x into y and y into x.

E(x, y) = max { K(x | y), K(y | x) } + O(log)

Universality. E is a metric (up to small terms). For every "reasonable" computable distance D, E(x,y) ≤ D(x,y) + O(1). If two objects are close in any computable sense, they are close in E.

Normalized (NID), scaled to [0, 1]:

NID(x,y) = max{K(x|y), K(y|x)} / max{K(x), K(y)}

NCD: replace K with a real compressor Z:

NCD(x,y) = (Z(xy) − min{Z(x),Z(y)}) / max{Z(x),Z(y)}

Why NCD works

  • Z(xy) − Z(x) estimates K(y | x). The compressor reuses patterns from x when it reaches y.
  • It needs no features, no alignment, and no domain knowledge. Any compressor and any file type will do.
  • It is near 0 for identical files. It is near 1 for unrelated files.

Compressor must be "normal"

  • Use one compressor for all three sizes. If you take the best of several, NCD can go above 1.
  • Mind the window. zlib only looks back 32 KB. If x is larger, y cannot see it, and NCD drifts to 1. lzma (with a huge dictionary) is safer.

Real uses: mtDNA trees of mammals, language family trees from the UN Human Rights text, music genres, plagiarism and malware families, and anomaly detection.

NCD in Python: the distance matrix DEMO

def Z(x: bytes) -> int:
    return len(lzma.compress(x, preset=9 | lzma.PRESET_EXTREME))

def ncd(x: bytes, y: bytes) -> float:
    zx, zy, zxy = Z(x), Z(y), Z(x + y)
    return (zxy - min(zx, zy)) / max(zx, zy)

def mutate(s: bytes, rate: float, seed: int) -> bytes:
    """Replace a fraction `rate` of bytes with other bytes from s itself."""
    r = random.Random(seed)
    return bytes(r.choice(s) if r.random() < rate else c for c in s)

r = random.Random(1)
dna_a = bytes(r.choice(b"ACGT") for _ in range(4000))
dna_b = bytes(r.choice(b"ACGT") for _ in range(4000))
eng  = b" ".join(r.choice([b"it was the best of times", ...]) for _ in range(150))
code = b"\n".join(r.choice([b"def f(n):", b"    if n < 2:", ...]) for _ in range(150))
docs = {"dnaA": dna_a, "dnaA'": mutate(dna_a, 0.10, 2),
        "dnaB": dna_b, "dnaB'": mutate(dna_b, 0.10, 3),
        "eng":  eng,   "eng'":  mutate(eng, 0.10, 4),
        "code": code,  "code'": mutate(code, 0.10, 5)}
names = list(docs)
D = {(a, b): ncd(docs[a], docs[b]) for a in names for b in names if a != b}

Each eng and code list has 8 phrases or lines. The full lists are in the test file.

         dnaA  dnaA'   dnaB  dnaB'    eng   eng'   code  code'
dnaA        -   0.29   0.84   0.83   0.95   0.95   0.95   0.95
dnaA'    0.29      -   0.84   0.83   0.95   0.95   0.95   0.95
dnaB     0.84   0.84      -   0.28   0.95   0.95   0.95   0.95
dnaB'    0.84   0.84   0.25      -   0.95   0.95   0.95   0.95
eng      0.93   0.93   0.93   0.93      -   0.48   0.75   0.91
eng'     0.93   0.93   0.92   0.93   0.83      -   0.91   0.87
code     0.93   0.93   0.92   0.93   0.74   0.91      -   0.47
code'    0.93   0.93   0.92   0.93   0.90   0.86   0.81      -

Read the matrix

  • Each file's nearest neighbour is its own mutated copy (0.25–0.48). The test file asserts this.
  • Two random DNA strings share the alphabet only. They score 0.84, which is close to "unrelated".
  • DNA vs text is about 0.93–0.95. There is nothing to reuse.
  • The matrix is not quite symmetric. Real compressors are not perfect, so Z(xy) ≠ Z(yx).

NCD by hand: three pairs from the matrix WORKED EXAMPLE

NCD(x,y) = (Z(xy) − min{Z(x),Z(y)}) / max{Z(x),Z(y)}

Read it as: "How many new bytes does y add once x is known, compared to the bigger file?" Sizes are lzma bytes from the demo.

PairZ(x)Z(y)Z(xy)WorkNCD
dnaA, dnaA'140014001812(1812−1400)/1400 = 412/14000.29
dnaA, eng14003681692(1692−368)/1400 = 1324/14000.95
eng, code368372648(648−368)/372 = 280/3720.75
  • dnaA, dnaA': 90% of the copy is shared. lzma only pays for the 10% of changed letters.
  • dnaA, eng: nothing to reuse. Z(xy) ≈ Z(x) + Z(y), so NCD is near 1.
  • eng, code: both are made of short English-like words. Some phrases help each other.

Sanity check the sizes

dnaA is 4000 random letters from ACGT. Each letter holds 2 bits, so the ideal size is 4000 × 2 / 8 = 1000 bytes. lzma gives 1400. The extra 400 bytes are overhead and model cost. So Z is only an upper bound on K, as promised.

Common mistakes

  • Dividing by the wrong size. The bottom is the max, the top subtracts the min. Swap them and NCD leaves [0,1].
  • Reading 0.95 as "5% similar". NCD is not a percentage. Values above about 0.9 just mean "no shared structure found".

Check yourself

Z(x) = 500, Z(y) = 800, Z(xy) = 900. What is NCD?

(900 − 500) / 800 = 0.5. Knowing x leaves only 400 new bytes to pay for.

Clustering by compression DEMO

def single_link(names, D):
    clusters = [[n] for n in names]
    while len(clusters) > 1:
        i, j = min(((i, j) for i in range(len(clusters))
                           for j in range(i + 1, len(clusters))),
                   key=lambda ij: min(D[a, b] for a in clusters[ij[0]]
                                               for b in clusters[ij[1]]))
        d = min(D[a, b] for a in clusters[i] for b in clusters[j])
        print(f"merge {clusters[i]} + {clusters[j]}  at {d:.2f}")
        clusters[i] = clusters[i] + clusters[j]; del clusters[j]
single_link(names, D)
merge ['dnaB'] + ["dnaB'"]  at 0.28
merge ['dnaA'] + ["dnaA'"]  at 0.29
merge ['code'] + ["code'"]  at 0.47
merge ['eng'] + ["eng'"]  at 0.48
merge ['eng', "eng'"] + ['code', "code'"]  at 0.75
merge ['dnaA', "dnaA'"] + ['dnaB', "dnaB'"]  at 0.83
merge ['dnaA', "dnaA'", 'dnaB', "dnaB'"] + ['eng', "eng'", 'code', "code'"]  at 0.95
dnaAdnaA' dnaBdnaB' engeng' codecode' 0.290.28 0.480.47 0.750.83 0.95

The tree found the structure

  • Pairs first, then "text-like" vs "DNA-like", then the root.
  • eng joins code before any DNA. Both are ASCII with spaces and English words.
  • No parser, no features. Just lzma. Cilibrasi & Vitányi used this idea on whole genomes and on languages.

Martin-Löf randomness INFINITE SEQUENCES

What makes an infinite 0/1 sequence random? Frequency rules like "half zeros" are not enough. 0101010… passes that test. We want a sequence to pass every effective test.

Martin-Löf test (1966): a computable list of sets of sequences U1 ⊇ U2 ⊇ …. Each Um is a c.e. union of cylinders [w], with measure μ(Um) ≤ 2−m.

A sequence ω fails the test if ω ∈ ∩m Um. It is ML-random if it fails no test.

  • Each test catches a set of measure 0. There are only countably many tests. So almost every sequence is ML-random.
  • There is a single universal test that catches everything any test catches.

Levin–Schnorr theorem (1973). ω is ML-random if and only if

∃c ∀n:  K(ω1 … ωn) ≥ n − c

"Random" (passes all tests) equals "incompressible" (every prefix). Two very different ideas give one class.

Properties of every ML-random sequence

  • Law of large numbers. Law of the iterated logarithm.
  • Every block of length k appears with frequency 2−k. It is "normal".
  • It is not computable. No program prints it.

Plain C fails here

With plain C, no sequence has C(ω1..n) ≥ n − c for all n. Martin-Löf showed this "complexity dips" effect. Prefix-free K fixes it.

Randomness deficiency HOW RANDOM?

Randomness deficiency of a length-n string, with respect to the uniform distribution:

δ(x) = n − K(x | n)

For a general computable P: δP(x) = −log P(x) − K(x | P).

Fact. P(δP(x) ≥ k) ≤ 2−k. Large deficiency is rare, so it is evidence against P.

Proof. Strings with K(x|P) ≤ −log P(x) − k have total probability at most ∑ 2−K(x|P) − k ≤ 2−k by Kraft. ∎

So δ is a universal test statistic. A deficiency of 30 bits is like a p-value of 2−30. And it holds for every computable test at once, not just the one you picked.

def deficiency_bits(x: bytes) -> int:
    """n - C(x) in bits: a lower bound on the true deficiency n - K(x), up to O(1)."""
    return 8 * len(x) - 8 * C(x)

tests = {
    "fair coin":      bernoulli_bytes(0.5, 80_000, seed=11),
    "biased p=0.1":   bernoulli_bytes(0.1, 80_000, seed=12),
    "period 7":       (b"\x5a\x13\x77\x00\xff\x42\x99" * 1500)[:10_000],
}
for name, x in tests.items():
    print(f"{name:<14} n={8*len(x)} bits   n - C(x) = {deficiency_bits(x):>6} bits")
fair coin      n=80000 bits   n - C(x) =    -88 bits
biased p=0.1   n=80000 bits   n - C(x) =  36128 bits
period 7       n=80000 bits   n - C(x) =  79608 bits
  • Fair coin: the compressor loses 88 bits of header. We find no evidence against "uniform", as expected.
  • Biased coin: 36128 bits of evidence that this is not a fair coin. That fits n(1 − H(0.1)) ≈ 42500, minus lzma's overhead.
  • Period 7: almost all of it is structure.

Chaitin's Ω: the halting probability A RANDOM REAL

Definition (Chaitin 1975). For a universal prefix machine U:

Ω = ∑p : U(p) halts 2−|p|

This is the chance that U halts when fed fair coin flips. By Kraft, 0 < Ω < 1.

Theorem. The first n bits of Ω decide halting for every program of length ≤ n.

Proof. Dovetail all programs. Add 2−|p| each time one halts, until the sum reaches 0.Ω1…Ωn. A program with |p| ≤ n that halts later would push the sum past Ω1..n + 2−n > Ω. That is impossible. So every program still running now never halts. ∎

Corollary. Ω is ML-random: K(Ω1..n) ≥ n − c.

Proof. From Ω1..n, find every halting program of length ≤ n and its output. Print a string that is not among those outputs. That string has K > n. We made it from Ω1..n, so n < K(Ω1..n) + c. ∎

Why Ω is remarkable

  • It is a precise, well-defined real number. Yet its bits are as patternless as coin flips.
  • It is left-c.e.. You can approximate it from below forever, but you never know how close you are.
  • It packs the halting problem as tightly as possible. Its first ~10,000 bits would settle Goldbach, Riemann, and any claim a short program can check.

Ω depends on U. Calude, Hertling, Khoussainov, Wang and Kučera–Slaman showed that the left-c.e. ML-random reals are exactly the Ωs of the different universal machines.

Chaitin's incompleteness theorem GÖDEL, VIA K

Theorem (Chaitin 1971). Let F be a sound, computably axiomatized theory (like ZFC). There is a constant LF such that F proves "K(x) > LF" for no specific string x.

Yet all but finitely many strings satisfy it.

Proof (Berry again)

  1. For a number L, write program PL. It lists all proofs of F in order. It prints the first x with a proof of "K(x) > L".
  2. |PL| ≤ log L + cF, since F's axioms are a fixed program.
  3. If it halts, K(x) ≤ log L + cF. By soundness, also K(x) > L.
  4. For L > log L + cF, that is a contradiction. So PL never halts. ∎

Reading it

  • A theory with n bits of axioms cannot prove that any string has much more than n bits of complexity.
  • "You can't get more out than you put in." A theorem cannot hold more information than its axioms plus the proof search.
  • The same holds for Ω. F can find at most LF + O(1) bits of Ω.
Gödel (1931)Chaitin (1971)
the liar: "I am unprovable"Berry: "the first string proven complex"
one strange sentencealmost all true sentences of a kind
needs self-referenceneeds only counting and search

In practice, LF is a few thousand bits for ZFC. You cannot prove that any specific megabyte file is incompressible, even though nearly all of them are.

Recap & check yourself (part 2) PRACTICE

What we added

  • Prefix-free programs obey Kraft, so 2−K(x) acts like a probability.
  • Coding theorem: likely under m means short, and back again.
  • On average, K matches Shannon's H.
  • NCD turns K into a real similarity score.
  • Random = passes every computable test = incompressible.
  • Ω and Chaitin's theorem put hard limits on proof.

Common mistake

"Chaitin says some strings have unknown K." It says more. A fixed theory can prove K(x) > L for no string at all, once L passes a constant. Yet almost every string has K that large.

Try these first, then open the answers

  1. What is the Kraft sum of {0, 10, 110, 111}?
    Answer1/2 + 1/4 + 1/8 + 1/8 = 1. The code is complete. You can't add a word without breaking prefix-freeness.
  2. If m(x) = 2−20, about how big is K(x)?
    AnswerAbout 20 bits, plus O(1). That is the coding theorem: K(x) = −log m(x) + O(1).
  3. Why can't a program print the bits of Ω?
    AnswerThe first n bits would tell you which programs of length ≤ n halt. That solves the halting problem, which no program can do.
  4. You flip a coin to make a 1 MB file. Can ZFC prove K(file) > 8 million bits?
    AnswerNo. The claim is almost surely true. But ZFC can't prove K(x) > L for any x once L passes its constant, which is far below 8 million.
  5. For two independent coin-flip strings, what is I(x:y)?
    AnswerAbout 0, up to log terms. K(x,y) ≈ K(x) + K(y), so neither tells you anything about the other.

MDL: Occam's razor as code length MODEL SELECTION

Two-part MDL (Rissanen 1978). Choose the model M that minimizes

L(M) + L(D | M)

First pay to describe the model. Then pay to describe the data using it. A complex model makes L(D|M) small, but L(M) big.

  • Ideal MDL uses K(M) + K(D | M). Practical MDL restricts to a model class. It uses (k/2) log n bits for k real parameters.
  • The (k/2) log n penalty equals BIC. Better versions include normalized maximum likelihood and Bayesian mixture codes.
  • Kolmogorov structure function: the best "sufficient statistic" of x is the smallest model that makes x look like a typical member.

Data: 20,000 bits from a source that repeats its last bit with probability 0.9. That is order-1 Markov. Which order k does MDL pick?

s = markov_source(20_000, seed=3)
print(f"{'k':>2}{'L(model)':>10}{'L(data|model)':>15}{'total':>10}")
best = None
for k in range(6):
    m, d = two_part_bits(s, k)
    print(f"{k:>2}{m:>10.0f}{d:>15.0f}{m + d:>10.0f}")
    if best is None or m + d < best[1]: best = (k, m + d)
print("MDL picks k =", best[0])
 k  L(model)  L(data|model)     total
 0         7          20000     20007
 1        14           9307      9321
 2        29           9304      9333
 3        57           9299      9356
 4       114           9293      9408
 5       229           9279      9508
MDL picks k = 1

two_part_bits counts next bits per context. It charges the empirical entropy for the data and 2k · ½ log n for the model. Higher orders fit a little better, but not enough to pay for their parameters.

Solomonoff induction UNIVERSAL PREDICTION

Universal prior on sequences (a monotone machine U):

M(x) = ∑p : U(p) starts with x 2−|p|

Predict with M(b | x) = M(xb) / M(x). Every program that fits the past gets a vote, weighted by 2−length.

Solomonoff's theorem (1978). Suppose the data comes from any computable measure μ. Then

∑t Eμ[(M(0|x<t) − μ(0|x<t))2] ≤ (ln 2 / 2) · K(μ)

The total error is finite. So predictions converge to the truth fast, for every computable world.

It is uncomputable, like K. AIXI (Hutter) adds actions and rewards on top. Practical versions limit the model class, as in our toy.

A toy: all "repeat this pattern" programs

def solomonoff_next(observed: str, max_period=12):
    """Mix all 'repeat pattern p' programs, prior 2^-(len(code))."""
    w = {"0": 0.0, "1": 0.0}
    for per in range(1, max_period + 1):
        for bits in product("01", repeat=per):
            pat = "".join(bits)
            gen = (pat * (len(observed) // per + 2))
            if gen.startswith(observed):
                prior = 2.0 ** -(2 * per + 1)   # per ones, a zero, then per bits
                w[gen[len(observed)]] += prior
    z = w["0"] + w["1"]
    return {b: round(v / z, 4) for b, v in w.items()}

for obs in ["0", "01", "0101", "011011", "0110110110"]:
    print(f"{obs:<11} -> P(next) = {solomonoff_next(obs)}")
0           -> P(next) = {'0': 0.7501, '1': 0.2499}
01          -> P(next) = {'0': 0.7501, '1': 0.2499}
0101        -> P(next) = {'0': 0.9723, '1': 0.0277}
011011      -> P(next) = {'0': 0.9925, '1': 0.0075}
0110110110  -> P(next) = {'0': 0.0001, '1': 0.9999}

After "0", the period-1 pattern "repeat 0" (a 3-bit code) has the biggest weight. After "0110110110", only period 3 and its multiples still fit, plus a few long patterns. They all but agree on "1".

Beyond K: logical depth and sophistication MEANINGFUL COMPLEXITY

K ranks a random string as the most complex. But a random string is boring. A DNA genome or a proof feels "complex" in a different way. It is structured and hard to make.

Logical depth (Bennett 1988). The running time of near-shortest programs:

depths(x) = min { time(p) : U(p) = x, |p| ≤ K(x) + s }

Deep objects hold the result of a long computation. You cannot shortcut it.

Sophistication (Koppel 1987). Split x's shortest description into model plus noise. The model is a finite set S ∋ x. The noise is x's index in S, which costs log|S| bits. Sophistication is the smallest K(S) over sets with K(S) + log|S| ≤ K(x) + c. So the two-part code is still near-optimal.

Related: Gell-Mann & Lloyd's effective complexity, and the Kolmogorov structure function.

ObjectKDepthSophistication
0nlowlowlow
n coin flipshighlow (just print)low (model: "any string")
digits of πlowmoderatelow
a genomehighhighhigh
a long proof or chess tablelow–midhighmid

Slow growth law

Bennett proved that depth cannot grow fast. A fast, simple process cannot create a deep object. Only long computations can. This gives a formal sense to "evolution took billions of years to make that".

Both measures depend on a significance parameter s or c. Both are even less computable than K.

Compression as a stand-in for K PRACTICE

def C(x: bytes) -> int:
    """Best of three real compressors, in bytes. An upper bound on K(x) + O(1)."""
    return min(len(zlib.compress(x, 9)), len(lzma.compress(x, preset=9)), len(bz2.compress(x, 9)))

samples = {
    "zeros":        bytes(N),
    "'ab' repeated": b"ab" * (N // 2),
    "English-ish":  (b"the quick brown fox jumps over the lazy dog " * 3000)[:N],
    "pi digits":    pi_digits(N).encode(),
    "random bytes": rng.randbytes(N),
}
for name, x in samples.items():
    print(f"{name:<15}{len(x):>8}{len(zlib.compress(x, 9)):>8}"
          f"{len(lzma.compress(x, preset=9)):>8}{len(bz2.compress(x, 9)):>8}")
x = samples["pi digits"]
print(f"pi: {8 * C(x) / len(x):.3f} bits/digit  vs  log2(10) = {math.log2(10):.3f}")
input               raw    zlib    lzma     bz2
zeros            100000     120     148      47
'ab' repeated    100000     122     152      43
English-ish      100000     358     192     171
pi digits        100000   48174   43732   43229
random bytes     100000  100041  100064  100808
pi: 3.458 bits/digit  vs  log2(10) = 3.322

N = 100_000, rng = random.Random(42). pi_digits uses Machin's formula with Python integers. It is 10 lines, in the test file.

What the table shows

  • Random bytes grow. No compressor beats the counting argument.
  • Repeats collapse to the compressor's header, about 50–150 bytes.
  • π is the lesson. The compressors only remove the ASCII waste, 8 bits down to about log210. But K(first n digits of π) ≈ log n + a few hundred bytes. Our pi_digits is that short program.

Compressors are weak models

They find repeats and skewed statistics. They miss arithmetic, physics and logic. So C(x) can sit far above K(x). The gap never shows itself. Large language models are much stronger compressors, and "compression = intelligence" is an active research idea (the Hutter Prize).

Pitfalls and misconceptions WATCH OUT

"zlib size is K"

It is only an upper bound, up to a constant. It can be wildly loose, as with π. You can never prove it is tight.

Constants on short strings

"K(0110) = 3" means nothing. The invariance constant is often thousands of bits. Use K for long objects and asymptotics.

"Random = high entropy"

Entropy belongs to a distribution. K belongs to one string. A fair coin (maximum entropy) can output 0n, which has tiny K.

Plain C vs prefix K

They differ by up to 2 log n. Plain C breaks subadditivity and Levin–Schnorr. Say which one you mean.

NCD mistakes

Mixing compressors breaks the [0,1] range. Files bigger than the window (32 KB for zlib) look unrelated. Headers make tiny files look far apart.

High K ≠ interesting

Noise has the highest K. For "meaningful" structure, look at depth, sophistication, or the model part of MDL.

Summary TAKEAWAYS

  • K(x) = length of the shortest program for x. The invariance theorem makes it machine-free, up to O(1).
  • K(x) ≤ |x| + c. Counting shows most strings reach that bound.
  • K is uncomputable (Berry). It is as hard as halting. We only get upper bounds.
  • Prefix-free K obeys Kraft. Its average matches Shannon's H.
  • Random = incompressible (Levin–Schnorr). Ω is random and holds the halting problem.
  • MDL, Solomonoff and NCD turn the theory into tools.
ResultStatement
Invariance|KU − KV| ≤ c
Counting< 2n−c strings have C < n−c
Coding theoremK(x) = −log m(x) + O(1)
EntropyE[K] = H + O(K(P))
SymmetryI(x:y) = I(y:x) + O(1)
ChaitinF can't prove K(x) > LF

Further reading

  • Li & Vitányi, An Introduction to Kolmogorov Complexity and Its Applications (4th ed., 2019)
  • Cover & Thomas, Elements of Information Theory, ch. 14
  • Downey & Hirschfeldt, Algorithmic Randomness and Complexity (2010)
  • Cilibrasi & Vitányi, "Clustering by Compression", IEEE Trans. IT (2005)

Glossary QUICK LOOKUP

TermMeaning
C(x)Plain complexity: shortest program for x, any programs allowed.
K(x)Prefix complexity: shortest program, from a prefix-free set.
Universal machine UOne machine that can run every other machine's programs.
Invariance constantFixed cost of switching machines. It does not depend on x.
IncompressibleC(x) ≥ |x| (or ≥ |x| − c). No pattern to exploit.
DovetailingRun all programs in turns, a few steps each, so none blocks.
Upper semi-computableYou can compute better and better upper bounds, never knowing when you are done.
Prefix-free codeNo word starts another word. Words end on their own.
Kraft inequality∑ 2−len ≤ 1 for any prefix-free code.
m(x)Universal prior: chance a random program prints x.
TermMeaning
K(x | y)Shortest program for x when y is given for free.
I(x:y)Shared information: K(x) + K(y) − K(x,y).
NCDNormalized compression distance: a real-compressor stand-in for NID.
Martin-Löf testA computable way to flag strings as "too regular".
Randomness deficiency|x| − K(x|n): how many bits of pattern x has.
Ω (Chaitin)Chance a random prefix program halts. Random and uncomputable.
MDLPick the model that minimizes model bits + data-given-model bits.
Solomonoff inductionPredict by weighting every program by 2−length.
Logical depthRun time of near-shortest programs. "Hard to make."
SophisticationSize of the smallest good model (set S) for x.