2 (** {1 Knuth's algorithm for prime numbers}
4 The Art of Computer Programming, vol 1, page 147.
6 The following code computes a table of the first `m` prime numbers.
7 Though there are more efficient ways of computing prime numbers,
8 the nice thing about this code is that it requires not less than
9 Bertrand's postulate (for `n > 1`, there is always a prime `p` such that
10 `n < p < 2n`) to be proved correct.
12 This program had been proved correct using Coq and an early version of
13 Why back in 2003, by Laurent Théry (INRIA Sophia-Antipolis): Laurent Théry,
14 Proving Pearl: Knuth's Algorithm for Prime Numbers, TPHOLs 2003.
15 Truly a tour de force, this proof includes the full proof of Bertrand's
16 postulate in Coq. Here, we simply focus on the program verification part,
17 posing Bertrand's postulate as a lemma that we do not prove.
19 Note: Knuth's code is entering the loop where a new prime number is
20 added, thus resulting into the immediate addition of 3 as `prime[1]`.
21 It allows subsequent division tests to start at `prime[1]=3`, thus
22 saving the division by `prime[0]=2`. We did something similar in the
23 code below, though the use of a while loop looks like we did a
24 special case for 3 as well. *)
29 use int.ComputerDivision
31 use number.Divisibility
36 predicate no_prime_in (l u: int) =
37 forall x: int. l < x < u -> not (prime x)
39 (** `p[0]..p[u-1]` are the first u prime numbers *)
40 predicate first_primes (p: int -> int) (u: int) =
43 (forall i j: int. 0 <= i < j < u -> p[i] < p[j]) /\
45 (forall i: int. 0 <= i < u -> prime p[i]) /\
47 (forall i: int. 0 <= i < u-1 -> no_prime_in p[i] p[i+1])
50 forall p: int -> int, u: int. 1 <= u -> first_primes p u ->
51 forall d: int. 2 <= d <= p[u-1] -> prime d ->
52 exists i: int. 0 <= i < u /\ d = p[i]
54 (** Bertrand's postulate, admitted as an axiom
55 (the label is there to suppress the warning issued by Why3) *)
56 axiom Bertrand_postulate [@W:non_conservative_extension:N] :
57 forall p: int. prime p -> not (no_prime_in p (2*p))
61 (** `prime_numbers m` returns an array containing the first `m`
63 let prime_numbers (m: int) : array int
65 ensures { result.length = m }
66 ensures { first_primes result.elts m }
70 let n = ref 5 in (* candidate for next prime *)
72 invariant { first_primes p.elts j }
73 invariant { p[j-1] < !n < 2*p[j-1] }
75 invariant { no_prime_in p[j-1] !n }
76 let rec test (k: int) variant { 2*p[j-1] - !n, j - k }
77 requires { 1 <= k < j }
78 requires { first_primes p.elts j }
79 requires { p[j-1] < !n < 2*p[j-1] }
81 requires { no_prime_in p[j-1] !n }
82 requires { forall i: int. 0 <= i < k -> not (divides p[i] !n) }
83 ensures { p[j-1] < !n /\ prime !n /\ no_prime_in p[j-1] !n }
84 = if mod !n p[k] = 0 then begin
85 assert { not (prime !n) }; n += 2; test 1
86 end else if div !n p[k] > p[k] then
97 exception BenchFailure
99 let bench () raises { BenchFailure -> true } =
100 let t = prime_numbers 100 in
101 if t[0] <> 2 then raise BenchFailure;
102 if t[1] <> 3 then raise BenchFailure;
103 if t[2] <> 5 then raise BenchFailure;
104 if t[3] <> 7 then raise BenchFailure;
105 if t[4] <> 11 then raise BenchFailure;
106 if t[5] <> 13 then raise BenchFailure;
107 if t[6] <> 17 then raise BenchFailure;
108 if t[7] <> 19 then raise BenchFailure;
109 if t[8] <> 23 then raise BenchFailure;
110 if t[9] <> 29 then raise BenchFailure;