Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

The halting problem and limits of computing

After this lesson: I can explain why no program can decide every question, and what too slow means.

60 min lesson3 commandsCompilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Some questions no program can answer

The halting problem asks whether a given program will ever stop on a given input. Alan Turing proved in 1936 that no program can answer it correctly for every program.

A second limit is time. Some problems can be solved, but only in more time than you have. This lesson separates the impossible from the merely too slow.

By the end of this lesson

Note

I can explain why no program can decide every question, and what too slow means.

Key words

WordWhat it means
Decidablea yes or no question that some program always answers correctly
Undecidablea question no program can answer correctly every time
Halting problemdoes this program stop on this input?
Brute forcetrying every possible answer
Subset sumcan some of these numbers add up to the target?
Intractablesolvable, but too slow once the input is large

The cells students fill in are left blank in this preview.

No program can check every program for stopping

Suppose someone writes halts(program, data), a checker that always answers True if the program stops and False if it runs for ever.

We can use it to build a troublemaker that does the opposite of what the checker predicts about it. Ask the checker about the troublemaker running on itself, and it cannot be right.

The troublemaker program

Code: python
# Suppose halts(program, data) always answered True or False correctly.
def troublemaker(program):
    if halts(program, program):
        while True:
            pass
    return "stopped"

# Now ask: does troublemaker stop when given itself?

Every answer the checker gives is wrong

Checker says about the troublemakerThe troublemaker thenSo the checker was
It stopsLoops for everWrong
It loops for everStops at onceWrong

The cells students fill in are left blank in this preview.

Waiting never proves a program loops

Running a program tells you when it stops. It never tells you that it never will, because there is always one more second to wait.

The Run below gives sleep five seconds, but the timeout command gives up after one. Giving up is a decision, not an answer.

Give up on a program after a second

Command
timeout 1 sleep 5 || echo gave up after one second

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Which questions are decidable

QuestionDecidable?Why
Is this list sorted?YesLook at each pair once
Does this program stop within a million steps?YesRun it for a million steps
Does this program stop on this input?NoIt is the halting problem
Will this program ever print hello?NoAnswering it would solve the halting problem
Do these two programs always give the same output?NoThe same reason

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people think undecidable means very hard, or that computers are not fast enough yet. Undecidable is proven impossible for any program, however fast. Intractable is different: a program exists, but it takes too long once the input is large.

Brute force doubles with every extra number

In subset sum you are given some numbers and a target. Brute force tries every subset and adds it up.

With n numbers there are 2 to the power n subsets, because each number is either in or out. One more number doubles the work. Run the demo, then add a number and watch the count.

Brute force on a small subset sum

Code: python
# Brute force: try every subset of the numbers, counting how many we try.
numbers = [3, 5, 8]
target = 8
n = len(numbers)
tried = 0
found = []
for pattern in range(2 ** n):
    total = 0
    chosen = []
    for i in range(n):
        # Bit i of the pattern says whether number i is in this subset.
        if (pattern // (2 ** i)) % 2 == 1:
            total = total + numbers[i]
            chosen.append(numbers[i])
    tried = tried + 1
    if total == target:
        found.append(chosen)
print("subsets tried:", tried)
print("subsets that add up to", target, ":", found)
# Add 13 to numbers and run again: how many subsets are tried now?

Doubling beats squaring

Numbers (n)n squared steps2 to the power n steps
101001,024
204001,048,576
309001,073,741,824
401,6001,099,511,627,776

The cells students fill in are left blank in this preview.

Two to the power 20 and 40

Command
python3 -c "print(2 ** 20, 2 ** 40)"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Years of brute force on 60 numbers

Command
python3 -c "print(2 ** 60 // 10 ** 9 // 31536000)"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Going further

Checking an answer to subset sum is quick, but finding one seems to need a search. Whether a quick way to find one exists is a famous open question, called P versus NP.

Write down two other puzzles where checking an answer is easy and finding one looks hard, such as a sudoku.

About this lab and its source: Compilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.