Recap and Warm-up

In our last lecture, we introduced Kolmogorov Complexity, , a powerful concept defining the information content of a string as the length of the shortest program that generates it.

A crucial point to remember is that we’re less concerned with the exact complexity of a single, concrete object. Why? Because there’s always a “dirty constant” (Schmutzfaktor), an additive overhead that depends on the chosen programming language. This makes precise measurement for a single string tricky. Instead, we focus on the asymptotic behavior for an infinite sequence of objects. As the objects get larger, this constant becomes negligible, and the true, underlying information content becomes clear.

Let’s start with a warm-up exercise to solidify this.

Bounding Complexity for Structured Sequences

Consider the set of words of the form , where the length is a number of the form for some natural numbers . How can we find an upper bound on ?

The strategy is always to devise a short program that generates .

# A program to generate x = 0^N where N = 2^i * 3^j * 5^k
function generate_x(i, j, k):
  # Calculate the large number N from the small exponents
  N = (2**i) * (3**j) * (5**k)
  
  # In a loop, print '0' N times
  output = ""
  for _ in range(N):
    output += '0'
  print(output)

To generate a specific from this family, the program needs the specific values of . The program that generates this would look like this:

# A specific program for a specific x
i = ... # The specific exponent for 2
j = ... # The specific exponent for 3
k = ... # The specific exponent for 5
 
N = (2**i) * (3**j) * (5**k)
print('0' * N)

The length of this program is the length of the code template (a constant, ) plus the length of the binary representations of the numbers and .

How large can these exponents be? Since , we know that , which implies . The same logic applies to and . The exponents are, at most, logarithmic in the length of .

The number of bits needed to represent a number like is roughly . So, the number of bits for our exponents is roughly .

Therefore, we can bound the complexity:

This demonstrates that strings with this kind of deep mathematical structure are highly compressible and have very low information content.

Defining Randomness

Kolmogorov complexity gives us something profound that probability theory cannot: a formal definition of randomness for a single object. The intuition is simple and beautiful:

An object is random if it has no pattern. The shortest way to describe it is to present the object itself.

In our formal language:

A binary string is random if it is incompressible. Formally,

A random string has no internal structure that a program could exploit to generate it from a shorter description.

The Existence of Random Strings

This definition would be hollow if random strings were a mere theoretical curiosity. However, a simple counting argument shows they are not only real but abundant.

Lemma 2.5: For every natural number , there exists a random binary string of length .

Proof by Counting

This is a classic application of the pigeonhole principle.

  1. The Objects to Describe (Pigeons): There are exactly distinct binary strings of length .
  2. The Possible Short Descriptions (Pigeonholes): A “short description” is a program with a length less than . The total number of binary strings (and thus possible programs) of length less than is:

We have strings that need a description, but only available short descriptions. Therefore, at least one string of length cannot be generated by any program shorter than . Its shortest program must have a length of at least , making it random.

In fact, we can make a much stronger statement: most strings are random. A similar counting argument shows that at least half of all binary strings are random (or very close to it). Randomness is the norm, not the exception.

Randomness for Numbers

We can extend this concept to natural numbers by considering their binary representation.

A natural number is random if its standard binary representation, , is a random string.

for some universal constant .

The exact length of the binary representation of is

The Invariance Theorem: A Robust Definition

A potential weakness of our definition is its reliance on a specific programming language. What if a string is compressible in Python but not in Java? The Invariance Theorem assures us this is not a major issue.

Theorem: For any two universal programming languages (e.g., Turing machines, Python, Java), and , there exists a constant such that for all strings :

This means the complexity of a string might change from one language to another, but only by a fixed additive constant. For large strings, this difference is negligible.

Proof Idea

We can write a program in language that functions as an interpreter (or Übersetzer) for language . This interpreter is a fixed program with a constant length, .

To generate a string in language , we can construct the following program:

  1. The code for the interpreter of (written in ).
  2. The shortest program for written in language .

This combined program is a valid program in language . It works by interpreting and executing the language code to produce . Its total length is . Since is the length of the shortest program in , it must be less than or equal to this construction.

Kolmogorov Complexity as a Proof Tool

Now we’ll see how this abstract concept can be used as a powerful research instrument to prove concrete mathematical theorems.

A New Proof for the Infinitude of Primes

We all know Euclid’s classic proof by contradiction. Here is a completely different argument based on information theory.

Lemma 2.6 (variant): There are infinitely many prime numbers.

Proof by Contradiction

  1. Assumption: Assume there are only a finite number of primes: .
  2. Representation: Any natural number can be uniquely described by its prime factorization using this finite set of primes: This means the list of exponents is a complete description of .
  3. Compression: We can write a program that takes these exponents and reconstructs . The primes are fixed and can be hardcoded. The only information needed to specify a particular is the list of its exponents.
    • The size of each exponent is at most .
    • The number of bits to represent each exponent is thus .
    • Since is a fixed constant, the total length of the description for is bounded by:
  4. Contradiction: We know that there are infinitely many random numbers. We can pick a random number that is large enough. For this random number, by definition: This leads to the inequality: The function grows asymptotically faster than . For a sufficiently large , this inequality cannot hold. This is a contradiction.
  5. Conclusion: Our assumption that there is a finite number of primes must be false.

This style of argument is incredibly powerful: if assuming a certain mathematical structure allows for too much compression (violating the existence of random objects), then that structure cannot exist.

Complexity of Words in a Recursive Language

Let’s connect complexity to the languages we defined earlier. What can we say about the complexity of words in a recursive (i.e., decidable) language?

Lemma 2.6: Let be an infinite, recursive language. Let be the -th word in (in canonical order). Then there exists a constant such that:

Proof Idea

Since is recursive, there exists an algorithm decide_L(y) that returns true if and false otherwise. We can use this to build a program that generates .

function generate_nth_word(n):
  # This part of the program is fixed and has constant size c_L
  # It includes the code for decide_L and the generator logic.
  
  counter = 0
  y = "" # Start with the first word in canonical order (lambda)
  
  while True:
    if decide_L(y):
      counter += 1
    
    if counter == n:
      print(y)
      return
      
    y = next_string_in_canonical_order(y)

This program’s only input is the integer . The length of this input is about . The rest of the program is a fixed constant. Therefore, the complexity of is bounded by .

A Crucial Caveat

Does this lemma imply that all words in a recursive language are simple (have low complexity)? No!

The key is that is the order of the word in the language, not its length. Consider the language . This language is recursive (the decider just always returns true). But what is the -th word? The number of words of length up to is about . So, a word of length will have an order that is roughly .

Plugging this into our bound:

This bound is trivial; it tells us nothing new. The lemma is only powerful for “sparse” languages, where the -th word grows much faster than .

The Uncomputability of Kolmogorov Complexity

We have a beautiful, robust definition of information. Now for the final, stunning conclusion: it is impossible to compute.

Theorem: The function is not computable.

Proof by Contradiction

  1. Assumption: Assume there exists an algorithm ComputeK(x) that, for any string , halts and returns the integer .
  2. Construction: We can use this hypothetical algorithm to build a new program, FindComplexString(n), which performs the following task:
    function FindComplexString(n):
      # This program takes an integer n as input.
      y = "" # Start with the first word in canonical order (lambda)
      
      while True:
        # Use our hypothetical algorithm to find the complexity of y
        if ComputeK(y) >= n:
          # We found the first string with complexity at least n.
          print(y)
          return 
        
        # Generate the next string in the sequence
        y = next_string_in_canonical_order(y) 
  3. Analysis: This program, FindComplexString(n), generates a specific string, let’s call it , which is the first string in canonical order with complexity at least . The program itself serves as a description for .
    • The code for the generator, the loop, and the call to ComputeK is fixed. Its length is a constant, .
    • The only variable part of the program is the input value . The length of the binary representation of is about .
    • Therefore, we have constructed a program of length that generates . This gives us an upper bound on the complexity of :
  4. Contradiction: By its very construction, is a string whose complexity is at least : Combining our two findings, we get the absurd inequality: For any fixed constant , we can choose an large enough such that . This is a fundamental contradiction.
  5. Conclusion: Our initial assumption, that an algorithm ComputeK(x) exists, must be false.

We have arrived at a profound and somewhat unsettling result. We have found what seems to be the “correct” definition of information and randomness, but it describes a property that is fundamentally beyond our ability to measure or compute.

Continue here: 05 Proving the Prime Number Theorem, Introduction to Finite Automata