Conceptintro
Algorithm correctness
Also called Correctness of algorithms, Partial and total correctness.
An algorithm is correct if it returns a valid output for every legal input; correctness is proved, not tested.
An algorithm is correct with respect to a specification when, for every input that the specification allows, it stops and gives an output that the specification accepts. Correctness is a claim about all legal inputs. There are usually infinitely many of them, or too many to try, so a finite set of tests cannot prove it. A proof can. It has two parts: partial correctness (the output is right if the algorithm stops) and termination (the algorithm does stop). Together they give total correctness.
In plain words
You cannot call an algorithm correct until you say what it must do. The statement of that task is the specification. It says which inputs are legal and which outputs are right for each of them.
An algorithm is then correct when two things hold for every legal input. It stops, and its output is right. A test runs the algorithm on a few inputs. A failed test shows a bug. A passed test shows nothing about the inputs that you did not try. A proof covers all inputs at once, and it explains why the algorithm works.
Most of the work in a proof is about loops and recursion. For a loop you find a fact that stays true at each step, and you show that this fact gives the right output when the loop ends. You also show that the loop does end.
The idea
Let be the set of inputs and the set of outputs. A specification is a pair of predicates: a precondition on inputs and a postcondition on an input and an output. An algorithm is correct for when
The statement has two parts. The part " stops on " is termination. The part " whenever stops" is partial correctness. A proof of each part is a different task, with different tools. Partial correctness uses loop invariants, or more generally Floyd's inductive assertions and Hoare triples. Termination uses a variant function: a quantity with values in a well-founded set, usually a non-negative integer, that drops strictly at each step. See termination proof.
For a recursive algorithm, partial correctness is proved by strong induction on a measure of the input that has no infinite decreasing sequence, for example its size. The induction hypothesis is that every recursive call on a smaller input meets the specification. The base cases are checked directly. Termination follows because every call is on a strictly smaller measure. For example, merge sort is correct on all arrays of length by strong induction on .
The statement says nothing about inputs outside . The algorithm may stop, fail or loop on them. This is why the precondition is part of the specification.
No algorithm decides, for every program and every specification, whether the program is totally correct (this follows from Rice's theorem). So each proof is built for its own algorithm. For a randomized algorithm the claim changes. A Monte Carlo algorithm is correct with probability at least for a stated . A Las Vegas algorithm is always correct, and its running time is random.
Testing and proof answer different questions. A test checks the formula above for one chosen . If gives a wrong output on that , the test finds a counterexample. If gives a right output, the formula is still open for every other . A proof covers all with . A proof is also a proof about a model: it uses mathematical integers, and a program on a real machine can differ from the model, for example through integer overflow.
Examples
The running example of this group of pages is integer square root. The specification is: the input is an integer , and the output is the integer with . For each exactly one such exists, namely . The algorithm is a binary search on the answer, see also integer square root.
ISQRT(n) ▷ n is an integer with n ≥ 0- 1
lo ← 0 - 2
hi ← n + 1 - 3
while hi − lo > 1 do - 4
mid ← lo + ⌊(hi − lo) / 2⌋ - 5
if mid · mid ≤ n then lo ← mid - 6
else hi ← mid - 7
r ← lo ▷ r is the result
Why it is correct. The loop invariant is : and .
- Start. After L1 and L2, and . Then , and because for . So holds.
- Step. Assume and . Put . Then and , so . If , the new pair satisfies . Otherwise , and the new pair satisfies .
- End. When the loop stops, . With this gives . Then says , and L7 sets . This is the postcondition.
- Termination. The new gap is or . Both are at most when . So the integer drops by at least 1 at each step, and it stays at least 1. The loop runs a finite number of times.
For the loop runs four times:
| step | lo | hi | hi − lo | mid | mid² ≤ 10 |
|---|---|---|---|---|---|
| 1 | 0 | 11 | 11 | 5 | no |
| 2 | 0 | 5 | 5 | 2 | yes |
| 3 | 2 | 5 | 3 | 3 | yes |
| 4 | 3 | 5 | 2 | 4 | no |
After step 4 the pair is , so , and .
A bug that tests can miss. Start with instead of . The invariant now fails at the start for , because is false. For the loop does not run, and the result is , but the right value is . For every other than 1 the buggy program returns the right value, because once . So a test set of thousands of inputs that leaves out passes. A proof attempt fails at once in the start step, for and for , and this points straight to the boundary.
A specification that is too weak. Take the postcondition alone. The program that always returns meets it, and it is useless. A specification must be strong enough to exclude every wrong answer that you care about. See postcondition.
Where it is used
Correctness proofs are the basis of the proof pages on this site. They are also the base of program verification tools, and of design by contract, where preconditions and postconditions are checked at run time as assertions. Where a proof is too costly, property-based testing and differential testing check the specification on many generated inputs. They find bugs and do not prove their absence.
References
- Cormen, Leiserson, Rivest and Stein, Introduction to Algorithms, fourth edition, Section 2.1
- C. A. R. Hoare, An axiomatic basis for computer programming, Communications of the ACM 12(10) (1969), pp. 576 to 580
- R. W. Floyd, Assigning meanings to programs, in Mathematical Aspects of Computer Science, Proceedings of Symposia in Applied Mathematics 19, AMS (1967), pp. 19 to 32
- Donald E. Knuth, The Art of Computer Programming, Volume 1, third edition, Section 1.2.1
About this page
The build computes these levels from the evidence in the repository. Each row says what the next level needs. Read what the levels mean.
| Ladder | Level | What the next level needs |
|---|---|---|
| Human proof | H0 no proof |
|
| Lean | L0 no Lean part |
|
| Visual | V0 none |
|
| Writing | W4 complete |
|
Tag KMBB0X Edit this page History Report an error Markdown JSON