1 (* ========================================================================= *)
2 (* HOL primality proving procedure, based on Pratt certificates. *)
3 (* ========================================================================= *)
5 needs "Library/prime.ml";;
13 (* ------------------------------------------------------------------------- *)
14 (* Mostly for compatibility. Should eliminate this eventually. *)
15 (* ------------------------------------------------------------------------- *)
17 let nat_mod_lemma = prove
18 (`!x y n:num. (x == y) (mod n) /\ y <= x ==> ?q. x = y + n * q`,
19 REPEAT GEN_TAC THEN REWRITE_TAC[num_congruent] THEN
20 DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
22 [INTEGER_RULE `(x == y) (mod &n) <=> &n divides (x - y)`] THEN
23 ASM_SIMP_TAC[INT_OF_NUM_SUB;
24 ARITH_RULE `x <= y ==> (y:num = x + d <=> y - x = d)`] THEN
25 REWRITE_TAC[GSYM num_divides; divides]);;
28 (`!x y n:num. (mod n) x y <=> ?q1 q2. x + n * q1 = y + n * q2`,
29 REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM cong] THEN
30 EQ_TAC THENL [ALL_TAC; NUMBER_TAC] THEN
31 MP_TAC(SPECL [`x:num`; `y:num`] LE_CASES) THEN
32 REWRITE_TAC[TAUT `a \/ b ==> c ==> d <=> (c /\ b) \/ (c /\ a) ==> d`] THEN
33 DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
35 ONCE_REWRITE_TAC[NUMBER_RULE
36 `(x:num == y) (mod n) <=> (y == x) (mod n)`]] THEN
37 MESON_TAC[nat_mod_lemma; ARITH_RULE `x + y * 0 = x`]);;
39 (* ------------------------------------------------------------------------- *)
40 (* Lemmas about previously defined terms. *)
41 (* ------------------------------------------------------------------------- *)
45 ~(p = 0) /\ ~(p = 1) /\ !m. 0 < m /\ m < p ==> coprime(p,m)`,
46 GEN_TAC THEN ASM_CASES_TAC `p = 0` THEN ASM_REWRITE_TAC[PRIME_0] THEN
47 ASM_CASES_TAC `p = 1` THEN ASM_REWRITE_TAC[PRIME_1] THEN
49 [DISCH_THEN(MP_TAC o MATCH_MP PRIME_COPRIME) THEN
50 DISCH_TAC THEN X_GEN_TAC `m:num` THEN STRIP_TAC THEN
51 FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
52 STRIP_TAC THEN ASM_REWRITE_TAC[COPRIME_1] THEN
53 ASM_MESON_TAC[NOT_LT; LT_REFL; DIVIDES_LE]; ALL_TAC] THEN
54 FIRST_ASSUM(X_CHOOSE_THEN `q:num` MP_TAC o MATCH_MP PRIME_FACTOR) THEN
55 REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `q:num`) THEN
56 SUBGOAL_THEN `~(coprime(p,q))` (fun th -> REWRITE_TAC[th]) THENL
57 [REWRITE_TAC[coprime; NOT_FORALL_THM] THEN
58 EXISTS_TAC `q:num` THEN ASM_REWRITE_TAC[DIVIDES_REFL] THEN
59 ASM_MESON_TAC[PRIME_1]; ALL_TAC] THEN
60 FIRST_ASSUM(MP_TAC o MATCH_MP DIVIDES_LE) THEN
61 ASM_REWRITE_TAC[LT_LE; LE_0] THEN
62 ASM_CASES_TAC `p:num = q` THEN ASM_REWRITE_TAC[] THEN
63 SIMP_TAC[] THEN DISCH_TAC THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
64 ASM_MESON_TAC[DIVIDES_ZERO]);;
66 let FINITE_NUMBER_SEGMENT = prove
67 (`!n. { m | 0 < m /\ m < n } HAS_SIZE (n - 1)`,
69 [SUBGOAL_THEN `{m | 0 < m /\ m < 0} = EMPTY` SUBST1_TAC THENL
70 [REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; LT]; ALL_TAC] THEN
71 REWRITE_TAC[HAS_SIZE; FINITE_RULES; CARD_CLAUSES] THEN
72 CONV_TAC NUM_REDUCE_CONV;
73 ASM_CASES_TAC `n = 0` THENL
74 [SUBGOAL_THEN `{m | 0 < m /\ m < SUC n} = EMPTY` SUBST1_TAC THENL
75 [ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN
76 ARITH_TAC; ALL_TAC] THEN
77 ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV THEN
78 REWRITE_TAC[HAS_SIZE_0];
79 SUBGOAL_THEN `{m | 0 < m /\ m < SUC n} = n INSERT {m | 0 < m /\ m < n}`
81 [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT] THEN
82 UNDISCH_TAC `~(n = 0)` THEN ARITH_TAC; ALL_TAC] THEN
83 UNDISCH_TAC `~(n = 0)` THEN
85 SIMP_TAC[FINITE_RULES; HAS_SIZE; CARD_CLAUSES] THEN
86 DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM; LT_REFL] THEN
89 let COPRIME_MOD = prove
90 (`!a n. ~(n = 0) ==> (coprime(a MOD n,n) <=> coprime(a,n))`,
92 FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV o LAND_CONV)
93 [MATCH_MP DIVISION th]) THEN REWRITE_TAC[coprime] THEN
94 AP_TERM_TAC THEN ABS_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
95 MESON_TAC[DIVIDES_ADD; DIVIDES_ADD_REVR; DIVIDES_ADD_REVL;
96 DIVIDES_LMUL; DIVIDES_RMUL]);;
98 (* ------------------------------------------------------------------------- *)
100 (* ------------------------------------------------------------------------- *)
103 (`!x y n. ~(n = 0) ==> ((x == y) (mod n) <=> (x MOD n = y MOD n))`,
104 REWRITE_TAC[cong; nat_mod] THEN
105 REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THENL
106 [ASM_CASES_TAC `x <= y` THENL
107 [CONV_TAC SYM_CONV THEN MATCH_MP_TAC MOD_EQ THEN EXISTS_TAC `q1 - q2`;
108 MATCH_MP_TAC MOD_EQ THEN EXISTS_TAC `q2 - q1`] THEN
109 REWRITE_TAC[RIGHT_SUB_DISTRIB] THEN
110 POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN ARITH_TAC;
111 MAP_EVERY EXISTS_TAC [`y DIV n`; `x DIV n`] THEN
112 UNDISCH_TAC `x MOD n = y MOD n` THEN
113 MATCH_MP_TAC(ARITH_RULE
114 `(y = dy + my) /\ (x = dx + mx) ==> (mx = my) ==> (x + dy = y + dx)`) THEN
115 ONCE_REWRITE_TAC[MULT_SYM] THEN ASM_SIMP_TAC[DIVISION]]);;
117 let CONG_MOD_0 = prove
118 (`!x y. (x == y) (mod 0) <=> (x = y)`,
119 REPEAT GEN_TAC THEN REWRITE_TAC[cong; nat_mod; MULT_CLAUSES; ADD_CLAUSES]);;
121 let CONG_MOD_1 = prove
122 (`!x y. (x == y) (mod 1)`,
123 REPEAT GEN_TAC THEN REWRITE_TAC[cong; nat_mod] THEN
124 MAP_EVERY EXISTS_TAC [`y:num`; `x:num`] THEN
125 REWRITE_TAC[MULT_CLAUSES; ADD_AC]);;
128 (`!x n. ((x == 0) (mod n) <=> n divides x)`,
129 REPEAT GEN_TAC THEN ASM_CASES_TAC `n = 0` THEN
130 ASM_REWRITE_TAC[DIVIDES_ZERO; CONG_MOD_0] THEN
131 ASM_SIMP_TAC[CONG; MOD_0; MOD_EQ_0] THEN
132 ONCE_REWRITE_TAC[MULT_SYM] THEN REWRITE_TAC[divides]);;
134 let CONG_SUB_CASES = prove
135 (`!x y n. (x == y) (mod n) <=>
136 if x <= y then (y - x == 0) (mod n)
137 else (x - y == 0) (mod n)`,
138 REPEAT GEN_TAC THEN REWRITE_TAC[cong; nat_mod] THEN
140 [GEN_REWRITE_TAC LAND_CONV [SWAP_EXISTS_THM]; ALL_TAC] THEN
141 REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
142 POP_ASSUM MP_TAC THEN ARITH_TAC);;
144 let CONG_MULT_LCANCEL = prove
145 (`!a n x y. coprime(a,n) /\ (a * x == a * y) (mod n) ==> (x == y) (mod n)`,
146 REPEAT GEN_TAC THEN ASM_CASES_TAC `a = 0` THENL
147 [ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_REWRITE_TAC[COPRIME_0] THEN
148 SIMP_TAC[CONG_MOD_1]; ALL_TAC] THEN
149 DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
150 ONCE_REWRITE_TAC[CONG_SUB_CASES] THEN
151 ASM_REWRITE_TAC[LE_MULT_LCANCEL] THEN
152 REWRITE_TAC[GSYM LEFT_SUB_DISTRIB; CONG_0] THEN
153 COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
154 ASM_MESON_TAC[COPRIME_DIVPROD; COPRIME_SYM]);;
156 let CONG_REFL = prove
157 (`!x n. (x == x) (mod n)`,
158 MESON_TAC[cong; nat_mod; ADD_CLAUSES; MULT_CLAUSES]);;
161 (`!x y n. (x == y) (mod n) <=> (y == x) (mod n)`,
162 REWRITE_TAC[cong; nat_mod] THEN MESON_TAC[]);;
164 let CONG_TRANS = prove
165 (`!x y z n. (x == y) (mod n) /\ (y == z) (mod n) ==> (x == z) (mod n)`,
166 REWRITE_TAC[cong; nat_mod] THEN
168 `(x + n * q1 = y + n * q2) /\
169 (y + n * q3 = z + n * q4)
170 ==> (x + n * (q1 + q3) = z + n * (q2 + q4))`]);;
172 (* ------------------------------------------------------------------------- *)
173 (* Euler totient function. *)
174 (* ------------------------------------------------------------------------- *)
176 let phi = new_definition
177 `phi(n) = CARD { m | 0 < m /\ m <= n /\ coprime(m,n) }`;;
180 (`phi(n) = CARD { m | coprime(m,n) /\ m < n}`,
181 REWRITE_TAC[phi] THEN
182 ASM_CASES_TAC `n = 0` THENL
184 ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
185 MESON_TAC[LT; NOT_LT];
187 ASM_CASES_TAC `n = 1` THENL
189 `({m | 0 < m /\ m <= n /\ coprime (m,n)} = {1}) /\
190 ({m | coprime (m,n) /\ m < n} = {0})`
191 (CONJUNCTS_THEN SUBST1_TAC)
192 THENL [ALL_TAC; SIMP_TAC[CARD_CLAUSES; FINITE_RULES; NOT_IN_EMPTY]] THEN
193 ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING] THEN
194 REWRITE_TAC[COPRIME_1] THEN REPEAT STRIP_TAC THEN ARITH_TAC;
196 AP_TERM_TAC THEN ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
197 X_GEN_TAC `m:num` THEN ASM_CASES_TAC `m = 0` THEN
198 ASM_REWRITE_TAC[LT] THENL
199 [ASM_MESON_TAC[COPRIME_0; COPRIME_SYM];
200 ASM_MESON_TAC[LE_LT; COPRIME_REFL; LT_NZ]]);;
202 let PHI_ANOTHER = prove
203 (`!n. ~(n = 1) ==> (phi(n) = CARD {m | 0 < m /\ m < n /\ coprime(m,n)})`,
204 REPEAT STRIP_TAC THEN REWRITE_TAC[phi] THEN
205 AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
206 ASM_MESON_TAC[LE_LT; COPRIME_REFL; COPRIME_1; LT_NZ]);;
208 let PHI_LIMIT = prove
210 GEN_TAC THEN REWRITE_TAC[PHI_ALT] THEN
211 GEN_REWRITE_TAC RAND_CONV [GSYM CARD_NUMSEG_LT] THEN
212 MATCH_MP_TAC CARD_SUBSET THEN ASM_REWRITE_TAC[FINITE_NUMSEG_LT] THEN
213 SIMP_TAC[SUBSET; IN_ELIM_THM]);;
215 let PHI_LIMIT_STRONG = prove
216 (`!n. ~(n = 1) ==> phi(n) <= n - 1`,
217 REPEAT STRIP_TAC THEN
218 MP_TAC(SPEC `n:num` FINITE_NUMBER_SEGMENT) THEN
219 ASM_SIMP_TAC[PHI_ANOTHER; HAS_SIZE] THEN
220 DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
221 MATCH_MP_TAC CARD_SUBSET THEN ASM_REWRITE_TAC[] THEN
222 SIMP_TAC[SUBSET; IN_ELIM_THM]);;
226 MP_TAC(SPEC `0` PHI_LIMIT) THEN REWRITE_TAC[ARITH] THEN ARITH_TAC);;
230 REWRITE_TAC[PHI_ALT; COPRIME_1; CARD_NUMSEG_LT]);;
232 let PHI_LOWERBOUND_1_STRONG = prove
233 (`!n. 1 <= n ==> 1 <= phi(n)`,
234 REPEAT STRIP_TAC THEN
235 SUBGOAL_THEN `1 = CARD {1}` SUBST1_TAC THENL
236 [SIMP_TAC[CARD_CLAUSES; NOT_IN_EMPTY; FINITE_RULES; ARITH]; ALL_TAC] THEN
237 REWRITE_TAC[phi] THEN MATCH_MP_TAC CARD_SUBSET THEN CONJ_TAC THENL
238 [SIMP_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; IN_ELIM_THM] THEN
239 REWRITE_TAC[ONCE_REWRITE_RULE[COPRIME_SYM] COPRIME_1] THEN
240 GEN_TAC THEN POP_ASSUM MP_TAC THEN ARITH_TAC;
241 MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{b | b <= n}` THEN
242 REWRITE_TAC[CARD_NUMSEG_LE; FINITE_NUMSEG_LE] THEN
243 SIMP_TAC[SUBSET; IN_ELIM_THM]]);;
245 let PHI_LOWERBOUND_1 = prove
246 (`!n. 2 <= n ==> 1 <= phi(n)`,
247 MESON_TAC[PHI_LOWERBOUND_1_STRONG; LE_TRANS; ARITH_RULE `1 <= 2`]);;
249 let PHI_LOWERBOUND_2 = prove
250 (`!n. 3 <= n ==> 2 <= phi(n)`,
251 REPEAT STRIP_TAC THEN
252 SUBGOAL_THEN `2 = CARD {1,(n-1)}` SUBST1_TAC THENL
253 [SIMP_TAC[CARD_CLAUSES; IN_INSERT; NOT_IN_EMPTY; FINITE_RULES; ARITH] THEN
254 ASM_SIMP_TAC[ARITH_RULE `3 <= n ==> ~(1 = n - 1)`]; ALL_TAC] THEN
255 REWRITE_TAC[phi] THEN MATCH_MP_TAC CARD_SUBSET THEN CONJ_TAC THENL
256 [SIMP_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; IN_ELIM_THM] THEN
257 GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
258 REWRITE_TAC[ONCE_REWRITE_RULE[COPRIME_SYM] COPRIME_1] THEN
260 ARITH_RULE `3 <= n ==> 0 < n - 1 /\ n - 1 <= n /\ 1 <= n`] THEN
261 REWRITE_TAC[coprime] THEN X_GEN_TAC `d:num` THEN STRIP_TAC THEN
262 MP_TAC(SPEC `n:num` COPRIME_1) THEN REWRITE_TAC[coprime] THEN
263 DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
264 SUBGOAL_THEN `1 = n - (n - 1)` SUBST1_TAC THENL
265 [UNDISCH_TAC `3 <= n` THEN ARITH_TAC;
266 ASM_SIMP_TAC[DIVIDES_SUB]];
267 MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{b | b <= n}` THEN
268 REWRITE_TAC[CARD_NUMSEG_LE; FINITE_NUMSEG_LE] THEN
269 SIMP_TAC[SUBSET; IN_ELIM_THM]]);;
271 let PHI_PRIME_EQ = prove
272 (`!n. (phi n = n - 1) /\ ~(n = 0) /\ ~(n = 1) <=> prime n`,
273 GEN_TAC THEN REWRITE_TAC[PRIME] THEN
274 ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
275 ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[PHI_1; ARITH] THEN
276 MP_TAC(SPEC `n:num` FINITE_NUMBER_SEGMENT) THEN
277 ASM_SIMP_TAC[PHI_ANOTHER; HAS_SIZE] THEN
278 DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
279 MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
280 `{m | 0 < m /\ m < n /\ coprime (m,n)} = {m | 0 < m /\ m < n}` THEN
283 REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
284 AP_TERM_TAC THEN ABS_TAC THEN
285 REWRITE_TAC[COPRIME_SYM] THEN CONV_TAC TAUT] THEN
286 EQ_TAC THEN SIMP_TAC[] THEN DISCH_TAC THEN
287 MATCH_MP_TAC CARD_SUBSET_EQ THEN ASM_REWRITE_TAC[] THEN
288 SIMP_TAC[SUBSET; IN_ELIM_THM]);;
290 let PHI_PRIME = prove
291 (`!p. prime p ==> phi p = p - 1`,
292 MESON_TAC[PHI_PRIME_EQ]);;
294 (* ------------------------------------------------------------------------- *)
295 (* Fermat's Little theorem. *)
296 (* ------------------------------------------------------------------------- *)
298 let DIFFERENCE_POS_LEMMA = prove
300 (?x1 x2. x1 * n + a = x2 * n + b)
301 ==> ?x. a = x * n + b`,
302 STRIP_TAC THEN EXISTS_TAC `x2 - x1` THEN
303 POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
304 REWRITE_TAC[RIGHT_SUB_DISTRIB] THEN ARITH_TAC);;
306 let ITSET_MODMULT = prove
307 (`!n s. FINITE s /\ ~(n = 0) /\ ~(n = 1) /\ coprime(a,n)
308 ==> (!b. b IN s ==> b < n)
309 ==> (ITSET (\x y. (x * y) MOD n) (IMAGE (\b. (a * b) MOD n) s) 1 =
310 (a EXP (CARD s) * ITSET (\x y. (x * y) MOD n) s 1) MOD n)`,
311 GEN_TAC THEN ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
312 ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[] THEN
313 ASM_CASES_TAC `coprime(a,n)` THEN ASM_REWRITE_TAC[] THEN
314 MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
315 MP_TAC(ISPECL [`\x y. (x * y) MOD n`; `1`] FINITE_RECURSION) THEN
316 W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
317 [ASM_SIMP_TAC[MOD_MULT_RMOD] THEN REWRITE_TAC[MULT_AC]; ALL_TAC] THEN
319 ASM_SIMP_TAC[IMAGE_CLAUSES; CARD_CLAUSES; FINITE_IMAGE] THEN CONJ_TAC THENL
320 [REWRITE_TAC[EXP; MULT_CLAUSES] THEN STRIP_TAC THEN CONV_TAC SYM_CONV THEN
321 MATCH_MP_TAC MOD_UNIQ THEN EXISTS_TAC `0` THEN
322 REWRITE_TAC[ADD_CLAUSES; MULT_CLAUSES] THEN
323 MAP_EVERY UNDISCH_TAC [`~(n = 0)`; `~(n = 1)`] THEN ARITH_TAC;
325 X_GEN_TAC `b:num` THEN X_GEN_TAC `s:num->bool` THEN
326 DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
327 REWRITE_TAC[IN_INSERT] THEN
328 REWRITE_TAC[TAUT `(a \/ b ==> c) <=> (a ==> c) /\ (b ==> c)`] THEN
329 REWRITE_TAC[FORALL_AND_THM] THEN
330 ASM_CASES_TAC `!b. b IN s ==> b < n` THEN ASM_REWRITE_TAC[] THEN
331 DISCH_TAC THEN SIMP_TAC[] THEN
332 DISCH_THEN(MP_TAC o SPEC `b:num`) THEN REWRITE_TAC[] THEN DISCH_TAC THEN
333 SUBGOAL_THEN `~((a * b) MOD n IN IMAGE (\b. (a * b) MOD n) s)`
334 (fun th -> REWRITE_TAC[th])
336 [REWRITE_TAC[IN_IMAGE] THEN
337 DISCH_THEN(X_CHOOSE_THEN `c:num` MP_TAC) THEN
338 DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
339 ASM_SIMP_TAC[GSYM CONG] THEN DISCH_TAC THEN
340 UNDISCH_TAC `~(b:num IN s)` THEN REWRITE_TAC[] THEN
341 SUBGOAL_THEN `b:num = c` (fun th -> ASM_REWRITE_TAC[th]) THEN
342 SUBGOAL_THEN `b MOD n = c MOD n` MP_TAC THENL
343 [ASM_SIMP_TAC[GSYM CONG] THEN
344 MATCH_MP_TAC CONG_MULT_LCANCEL THEN
345 EXISTS_TAC `a:num` THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
346 ASM_SIMP_TAC[MOD_LT]; ALL_TAC] THEN
347 REWRITE_TAC[EXP] THEN
348 ASM_SIMP_TAC[MOD_MULT_LMOD; MOD_MULT_RMOD] THEN
349 REWRITE_TAC[MULT_AC]);;
351 let ITSET_MODMULT_COPRIME = prove
352 (`!n s. FINITE s /\ (!b. b IN s ==> coprime(b,n)) /\ ~(n = 0)
353 ==> coprime(ITSET (\x y. (x * y) MOD n) s 1,n)`,
354 GEN_TAC THEN ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
355 REWRITE_TAC[IMP_CONJ] THEN
356 MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
357 MP_TAC(ISPECL [`\x y. (x * y) MOD n`; `1`] FINITE_RECURSION) THEN
358 W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
359 [ASM_SIMP_TAC[MOD_MULT_RMOD] THEN REWRITE_TAC[MULT_AC]; ALL_TAC] THEN
361 ASM_SIMP_TAC[IMAGE_CLAUSES; CARD_CLAUSES; FINITE_IMAGE] THEN
362 REWRITE_TAC[ONCE_REWRITE_RULE[COPRIME_SYM] COPRIME_1] THEN
363 REWRITE_TAC[IN_INSERT] THEN
364 REWRITE_TAC[TAUT `(a \/ b ==> c) <=> (a ==> c) /\ (b ==> c)`] THEN
365 REWRITE_TAC[FORALL_AND_THM] THEN
366 MAP_EVERY X_GEN_TAC [`x:num`; `s:num->bool`] THEN
367 ASM_CASES_TAC `!b. b IN s ==> coprime(b,n)` THEN ASM_REWRITE_TAC[] THEN
368 STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC `x:num`) THEN
369 ASM_SIMP_TAC[COPRIME_MOD; ONCE_REWRITE_RULE[COPRIME_SYM] COPRIME_MUL]);;
371 let FERMAT_LITTLE = prove
372 (`!a n. coprime(a,n) ==> (a EXP (phi n) == 1) (mod n)`,
374 ASM_CASES_TAC `n = 0` THEN
375 ASM_SIMP_TAC[COPRIME_0; PHI_0; CONG_MOD_0] THEN CONV_TAC NUM_REDUCE_CONV THEN
376 ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[CONG_MOD_1] THEN DISCH_TAC THEN
378 `{ c | ?b. 0 < b /\ b < n /\ coprime(b,n) /\ (c = (a * b) MOD n) } =
379 { b | 0 < b /\ b < n /\ coprime(b,n) }`
381 [REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
382 X_GEN_TAC `c:num` THEN EQ_TAC THENL
383 [DISCH_THEN(X_CHOOSE_THEN `b:num` MP_TAC) THEN
384 REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
385 DISCH_THEN SUBST1_TAC THEN ASM_SIMP_TAC[DIVISION] THEN
386 MATCH_MP_TAC(TAUT `b /\ (~a ==> ~b) ==> a /\ b`) THEN
387 SIMP_TAC[ARITH_RULE `~(0 < n) <=> (n = 0)`] THEN
388 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_SIMP_TAC[COPRIME_0] THEN
389 SUBGOAL_THEN `coprime(n,a * b)` MP_TAC THENL
390 [MATCH_MP_TAC COPRIME_MUL THEN
391 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
392 SUBGOAL_THEN `a * b = (a * b) DIV n * n + (a * b) MOD n`
393 (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
394 THENL [ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
395 REWRITE_TAC[coprime] THEN REPEAT STRIP_TAC THEN
396 FIRST_X_ASSUM MATCH_MP_TAC THEN
397 ASM_SIMP_TAC[DIVIDES_ADD; DIVIDES_LMUL; DIVIDES_REFL]; ALL_TAC] THEN
398 STRIP_TAC THEN MP_TAC(SPECL [`a:num`; `n:num`] BEZOUT) THEN
399 DISCH_THEN(X_CHOOSE_THEN `d:num`
400 (X_CHOOSE_THEN `x:num` (X_CHOOSE_THEN `y:num`
401 (CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)))) THEN
402 SUBGOAL_THEN `d = 1` SUBST_ALL_TAC THENL
403 [ASM_MESON_TAC[coprime]; ALL_TAC] THEN
405 [EXISTS_TAC `(c * x) MOD n` THEN
406 MATCH_MP_TAC(TAUT `(~a ==> ~c) /\ b /\ c /\ d ==> a /\ b /\ c /\ d`) THEN
408 [SIMP_TAC[ARITH_RULE `~(0 < n) <=> (n = 0)`] THEN
409 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_SIMP_TAC[COPRIME_0];
411 ASM_SIMP_TAC[DIVISION] THEN CONJ_TAC THENL
412 [SUBGOAL_THEN `coprime(n,c * x)` MP_TAC THENL
413 [MATCH_MP_TAC COPRIME_MUL THEN
414 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_REWRITE_TAC[] THEN
415 REWRITE_TAC[coprime; GSYM DIVIDES_ONE] THEN
416 FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
417 SIMP_TAC[DIVIDES_SUB; DIVIDES_LMUL; DIVIDES_RMUL; DIVIDES_REFL];
419 SUBGOAL_THEN `c * x = (c * x) DIV n * n + (c * x) MOD n`
420 (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
421 THENL [ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
422 REWRITE_TAC[coprime] THEN REPEAT STRIP_TAC THEN
423 FIRST_X_ASSUM MATCH_MP_TAC THEN
424 ASM_SIMP_TAC[DIVIDES_ADD; DIVIDES_LMUL; DIVIDES_REFL]; ALL_TAC] THEN
425 ASM_SIMP_TAC[MOD_MULT_RMOD] THEN CONV_TAC SYM_CONV THEN
426 MATCH_MP_TAC MOD_UNIQ THEN EXISTS_TAC `c * y:num` THEN
427 ASM_REWRITE_TAC[GSYM MULT_ASSOC] THEN
428 ONCE_REWRITE_TAC[ARITH_RULE
429 `(a * c * x = b:num) <=> (c * a * x = b)`] THEN
430 FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
431 `(a - b = 1) ==> (a = b + 1)`)) THEN
432 REWRITE_TAC[LEFT_ADD_DISTRIB; MULT_CLAUSES; MULT_AC];
434 EXISTS_TAC `(c * (n - y MOD n)) MOD n` THEN
435 MATCH_MP_TAC(TAUT `(~a ==> ~c) /\ b /\ c /\ d ==> a /\ b /\ c /\ d`) THEN
437 [SIMP_TAC[ARITH_RULE `~(0 < n) <=> (n = 0)`] THEN
438 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_SIMP_TAC[COPRIME_0];
440 ASM_SIMP_TAC[DIVISION] THEN CONJ_TAC THENL
441 [SUBGOAL_THEN `coprime(n,c * (n - y MOD n))` MP_TAC THENL
442 [MATCH_MP_TAC COPRIME_MUL THEN
443 ONCE_REWRITE_TAC[COPRIME_SYM] THEN ASM_REWRITE_TAC[] THEN
444 REWRITE_TAC[coprime; GSYM DIVIDES_ONE] THEN
445 FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
446 X_GEN_TAC `e:num` THEN STRIP_TAC THEN MATCH_MP_TAC DIVIDES_SUB THEN
447 ASM_SIMP_TAC[DIVIDES_RMUL; DIVIDES_REFL] THEN
448 MATCH_MP_TAC DIVIDES_LMUL THEN
449 SUBGOAL_THEN `y = (y DIV n) * n + y MOD n` SUBST1_TAC THENL
450 [ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
451 MATCH_MP_TAC DIVIDES_ADD THEN
452 ASM_SIMP_TAC[DIVIDES_LMUL; DIVIDES_REFL] THEN
453 MATCH_MP_TAC DIVIDES_ADD_REVR THEN
454 EXISTS_TAC `n - y MOD n` THEN ASM_REWRITE_TAC[] THEN
455 ASM_SIMP_TAC[ARITH_RULE `m < n ==> ((n - m) + m = n:num)`;
458 SUBGOAL_THEN `!x. c * x = (c * x) DIV n * n + (c * x) MOD n`
459 (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
460 THENL [ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
461 REWRITE_TAC[coprime] THEN REPEAT STRIP_TAC THEN
462 FIRST_X_ASSUM MATCH_MP_TAC THEN
463 ASM_SIMP_TAC[DIVIDES_ADD; DIVIDES_LMUL; DIVIDES_REFL]; ALL_TAC] THEN
464 ASM_SIMP_TAC[MOD_MULT_RMOD] THEN
465 CONV_TAC SYM_CONV THEN MATCH_MP_TAC MOD_UNIQ THEN
466 ASM_REWRITE_TAC[] THEN MATCH_MP_TAC DIFFERENCE_POS_LEMMA THEN
468 [ONCE_REWRITE_TAC[ARITH_RULE
469 `c <= a * c * x <=> c * 1 <= c * a * x`] THEN
470 REWRITE_TAC[LE_MULT_LCANCEL] THEN DISJ2_TAC THEN
471 REWRITE_TAC[ARITH_RULE `1 <= n <=> ~(n = 0)`; MULT_EQ_0;
472 SUB_EQ_0; DE_MORGAN_THM] THEN
473 UNDISCH_TAC `coprime(a,n)` THEN ONCE_REWRITE_TAC[COPRIME_SYM] THEN
474 ASM_CASES_TAC `a = 0` THEN ASM_REWRITE_TAC[COPRIME_0] THEN
475 DISCH_TAC THEN ASM_SIMP_TAC[DIVISION; NOT_LE]; ALL_TAC] THEN
476 MAP_EVERY EXISTS_TAC [`c * x`; `c * a * (1 + y DIV n)`] THEN
477 REWRITE_TAC[LEFT_ADD_DISTRIB; LEFT_SUB_DISTRIB] THEN
478 MATCH_MP_TAC(ARITH_RULE
479 `y <= n /\ (a + n = x + y) ==> (a + (n - y) = x)`) THEN
481 [REWRITE_TAC[MULT_ASSOC] THEN REWRITE_TAC[LE_MULT_LCANCEL] THEN
482 ASM_SIMP_TAC[LT_IMP_LE; DIVISION]; ALL_TAC] THEN
483 REWRITE_TAC[LEFT_ADD_DISTRIB; RIGHT_ADD_DISTRIB; MULT_CLAUSES] THEN
484 REWRITE_TAC[GSYM ADD_ASSOC; GSYM MULT_ASSOC] THEN
485 REWRITE_TAC[ARITH_RULE
486 `(x + a * c * n = c * a * n + y) <=> (x = y)`] THEN
487 FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
488 `(n * x - a * y = 1) ==> (x * n = a * y + 1)`)) THEN
489 SUBGOAL_THEN `y = (y DIV n) * n + y MOD n`
490 (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
491 THENL [ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
492 REWRITE_TAC[LEFT_ADD_DISTRIB; RIGHT_ADD_DISTRIB; MULT_CLAUSES] THEN
493 REWRITE_TAC[MULT_AC; ADD_AC]];
496 `{c | ?b. 0 < b /\ b < n /\ coprime (b,n) /\ (c = (a * b) MOD n)} =
497 IMAGE (\b. (a * b) MOD n) {b | 0 < b /\ b < n /\ coprime (b,n)}`
499 [REWRITE_TAC[IMAGE; EXTENSION; IN_ELIM_THM; CONJ_ASSOC]; ALL_TAC] THEN
500 DISCH_THEN(MP_TAC o AP_TERM `ITSET (\x y. (x * y) MOD n)`) THEN
501 DISCH_THEN(MP_TAC o C AP_THM `1`) THEN
502 SUBGOAL_THEN `FINITE {b | 0 < b /\ b < n /\ coprime (b,n)} /\
503 !b. b IN {b | 0 < b /\ b < n /\ coprime (b,n)} ==> b < n`
505 [CONJ_TAC THENL [ALL_TAC; SIMP_TAC[IN_ELIM_THM]] THEN
506 MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{b | 0 < b /\ b < n}` THEN
507 REWRITE_TAC[REWRITE_RULE[HAS_SIZE] FINITE_NUMBER_SEGMENT] THEN
508 SIMP_TAC[SUBSET; IN_ELIM_THM]; ALL_TAC] THEN
509 ASM_SIMP_TAC[REWRITE_RULE[IMP_IMP]
511 ASM_SIMP_TAC[GSYM PHI_ANOTHER] THEN
512 DISCH_THEN(MP_TAC o AP_TERM `(MOD)`) THEN
513 DISCH_THEN(MP_TAC o C AP_THM `n:num`) THEN
514 ASM_SIMP_TAC[MOD_MOD_REFL] THEN ASM_SIMP_TAC[GSYM CONG] THEN
515 GEN_REWRITE_TAC (LAND_CONV o RATOR_CONV o RAND_CONV)
516 [ARITH_RULE `x = x * 1`] THEN
517 GEN_REWRITE_TAC (LAND_CONV o RATOR_CONV o LAND_CONV) [MULT_SYM] THEN
518 DISCH_TAC THEN MATCH_MP_TAC CONG_MULT_LCANCEL THEN
519 EXISTS_TAC `ITSET (\x y. (x * y) MOD n)
520 {b | 0 < b /\ b < n /\ coprime (b,n)} 1` THEN
521 ASM_REWRITE_TAC[] THEN
522 ASM_SIMP_TAC[ITSET_MODMULT_COPRIME; IN_ELIM_THM]);;
524 let FERMAT_LITTLE_PRIME = prove
525 (`!p a. prime p ==> (a EXP p == a) (mod p)`,
526 REPEAT STRIP_TAC THEN
527 FIRST_ASSUM(MP_TAC o SPEC `a:num` o MATCH_MP PRIME_COPRIME) THEN
528 ONCE_REWRITE_TAC[COPRIME_SYM] THEN STRIP_TAC THENL
529 [ASM_REWRITE_TAC[EXP_ONE; CONG_REFL];
530 MATCH_MP_TAC CONG_TRANS THEN EXISTS_TAC `0` THEN
531 GEN_REWRITE_TAC RAND_CONV [CONG_SYM] THEN ASM_REWRITE_TAC[CONG_0] THEN
532 ASM_MESON_TAC[DIVIDES_EXP; DIVIDES_EXP2; PRIME_0];
534 FIRST_ASSUM(MP_TAC o MATCH_MP FERMAT_LITTLE) THEN
535 ASM_SIMP_TAC[snd(EQ_IMP_RULE (SPEC_ALL PHI_PRIME_EQ))] THEN
536 REWRITE_TAC[cong; nat_mod] THEN
537 DISCH_THEN(X_CHOOSE_THEN `q1:num` (X_CHOOSE_THEN `q2:num` MP_TAC)) THEN
538 DISCH_THEN(MP_TAC o AP_TERM `( * ) a`) THEN
539 REWRITE_TAC[LEFT_ADD_DISTRIB; GSYM(CONJUNCT2 EXP)] THEN
540 GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [MULT_SYM] THEN
541 REWRITE_TAC[MULT_CLAUSES; GSYM MULT_ASSOC] THEN
542 ASM_MESON_TAC[ARITH_RULE `~(p = 0) ==> (SUC(p - 1) = p)`; PRIME_0]);;
544 (* ------------------------------------------------------------------------- *)
545 (* Lucas's theorem. *)
546 (* ------------------------------------------------------------------------- *)
548 let LUCAS_COPRIME_LEMMA = prove
549 (`!m n a. ~(m = 0) /\ (a EXP m == 1) (mod n) ==> coprime(a,n)`,
550 REPEAT GEN_TAC THEN ASM_CASES_TAC `n = 0` THENL
551 [ASM_REWRITE_TAC[CONG_MOD_0; EXP_EQ_1] THEN
552 ASM_CASES_TAC `m = 0` THEN ASM_REWRITE_TAC[] THEN
553 ONCE_REWRITE_TAC[COPRIME_SYM] THEN SIMP_TAC[COPRIME_1];
555 ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[COPRIME_1] THEN
556 REPEAT STRIP_TAC THEN
557 REWRITE_TAC[coprime] THEN X_GEN_TAC `d:num` THEN STRIP_TAC THEN
558 UNDISCH_TAC `(a EXP m == 1) (mod n)` THEN
559 ASM_SIMP_TAC[CONG] THEN
560 SUBGOAL_THEN `1 MOD n = 1` SUBST1_TAC THENL
561 [MATCH_MP_TAC MOD_UNIQ THEN EXISTS_TAC `0` THEN
562 REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES] THEN
563 MAP_EVERY UNDISCH_TAC [`~(n = 0)`; `~(n = 1)`] THEN ARITH_TAC;
566 SUBGOAL_THEN `d divides (a EXP m) MOD n` MP_TAC THENL
567 [ALL_TAC; ASM_SIMP_TAC[DIVIDES_ONE]] THEN
568 MATCH_MP_TAC DIVIDES_ADD_REVR THEN
569 EXISTS_TAC `a EXP m DIV n * n` THEN
570 ASM_SIMP_TAC[GSYM DIVISION; DIVIDES_LMUL] THEN
571 SUBGOAL_THEN `m = SUC(m - 1)` SUBST1_TAC THENL
572 [UNDISCH_TAC `~(m = 0)` THEN ARITH_TAC;
573 ASM_SIMP_TAC[EXP; DIVIDES_RMUL]]);;
575 let LUCAS_WEAK = prove
577 (a EXP (n - 1) == 1) (mod n) /\
578 (!m. 0 < m /\ m < n - 1 ==> ~(a EXP m == 1) (mod n))
580 REPEAT STRIP_TAC THEN
581 ASM_SIMP_TAC[GSYM PHI_PRIME_EQ; PHI_LIMIT_STRONG; GSYM LE_ANTISYM;
582 ARITH_RULE `2 <= n ==> ~(n = 0) /\ ~(n = 1)`] THEN
583 FIRST_X_ASSUM(MP_TAC o SPEC `phi n`) THEN
584 SUBGOAL_THEN `coprime(a,n)` (fun th -> SIMP_TAC[FERMAT_LITTLE; th]) THENL
585 [MATCH_MP_TAC LUCAS_COPRIME_LEMMA THEN EXISTS_TAC `n - 1` THEN
586 ASM_SIMP_TAC [ARITH_RULE `2 <= n ==> ~(n - 1 = 0)`]; ALL_TAC] THEN
587 REWRITE_TAC[GSYM NOT_LT] THEN
588 MATCH_MP_TAC(TAUT `a ==> ~(a /\ b) ==> ~b`) THEN
589 ASM_SIMP_TAC[PHI_LOWERBOUND_1; ARITH_RULE `1 <= n ==> 0 < n`]);;
593 (a EXP (n - 1) == 1) (mod n) /\
594 (!p. prime(p) /\ p divides (n - 1)
595 ==> ~(a EXP ((n - 1) DIV p) == 1) (mod n))
597 REPEAT STRIP_TAC THEN
598 FIRST_ASSUM(ASSUME_TAC o MATCH_MP(ARITH_RULE `2 <= n ==> ~(n = 0)`)) THEN
599 MATCH_MP_TAC LUCAS_WEAK THEN EXISTS_TAC `a:num` THEN ASM_REWRITE_TAC[] THEN
600 REWRITE_TAC[TAUT `a ==> ~b <=> ~(a /\ b)`; GSYM NOT_EXISTS_THM] THEN
601 ONCE_REWRITE_TAC[num_WOP] THEN
602 DISCH_THEN(X_CHOOSE_THEN `m:num` STRIP_ASSUME_TAC) THEN
603 FIRST_ASSUM(ASSUME_TAC o MATCH_MP(ARITH_RULE `0 < n ==> ~(n = 0)`)) THEN
604 SUBGOAL_THEN `m divides (n - 1)` MP_TAC THENL
605 [REWRITE_TAC[divides] THEN ONCE_REWRITE_TAC[MULT_SYM] THEN
606 ASM_SIMP_TAC[GSYM MOD_EQ_0] THEN
607 MATCH_MP_TAC(ARITH_RULE `~(0 < n) ==> (n = 0)`) THEN DISCH_TAC THEN
608 FIRST_X_ASSUM(MP_TAC o SPEC `(n - 1) MOD m`) THEN
609 ASM_SIMP_TAC[DIVISION] THEN CONJ_TAC THENL
610 [MATCH_MP_TAC LT_TRANS THEN EXISTS_TAC `m:num` THEN
611 ASM_SIMP_TAC[DIVISION]; ALL_TAC] THEN
612 MATCH_MP_TAC CONG_MULT_LCANCEL THEN
613 EXISTS_TAC `a EXP ((n - 1) DIV m * m)` THEN CONJ_TAC THENL
614 [ONCE_REWRITE_TAC[COPRIME_SYM] THEN MATCH_MP_TAC COPRIME_EXP THEN
615 ONCE_REWRITE_TAC[COPRIME_SYM] THEN MATCH_MP_TAC LUCAS_COPRIME_LEMMA THEN
616 EXISTS_TAC `m:num` THEN ASM_SIMP_TAC[]; ALL_TAC] THEN
617 REWRITE_TAC[GSYM EXP_ADD] THEN
618 ASM_SIMP_TAC[GSYM DIVISION] THEN REWRITE_TAC[MULT_CLAUSES] THEN
619 ONCE_REWRITE_TAC[MULT_SYM] THEN REWRITE_TAC[GSYM EXP_EXP] THEN
620 UNDISCH_TAC `(a EXP (n - 1) == 1) (mod n)` THEN
621 UNDISCH_TAC `(a EXP m == 1) (mod n)` THEN
622 ASM_SIMP_TAC[CONG] THEN REPEAT DISCH_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
623 EXISTS_TAC `((a EXP m) MOD n) EXP ((n - 1) DIV m) MOD n` THEN
624 CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[MOD_EXP_MOD]] THEN
625 ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[MOD_EXP_MOD] THEN
626 REWRITE_TAC[EXP_ONE]; ALL_TAC] THEN
627 REWRITE_TAC[divides] THEN
628 DISCH_THEN(X_CHOOSE_THEN `r:num` SUBST_ALL_TAC) THEN
629 SUBGOAL_THEN `~(r = 1)` MP_TAC THENL
630 [UNDISCH_TAC `m < m * r` THEN CONV_TAC CONTRAPOS_CONV THEN
631 SIMP_TAC[MULT_CLAUSES; LT_REFL]; ALL_TAC] THEN
632 DISCH_THEN(MP_TAC o MATCH_MP PRIME_FACTOR) THEN
633 DISCH_THEN(X_CHOOSE_THEN `p:num` MP_TAC) THEN STRIP_TAC THEN
634 UNDISCH_TAC `!p. prime p /\ p divides m * r
635 ==> ~(a EXP ((m * r) DIV p) == 1) (mod n)` THEN
636 DISCH_THEN(MP_TAC o SPEC `p:num`) THEN ASM_SIMP_TAC[DIVIDES_LMUL] THEN
637 SUBGOAL_THEN `(m * r) DIV p = m * (r DIV p)` SUBST1_TAC THENL
638 [MATCH_MP_TAC DIV_UNIQ THEN EXISTS_TAC `0` THEN
639 UNDISCH_TAC `prime p` THEN
640 ASM_CASES_TAC `p = 0` THEN ASM_REWRITE_TAC[PRIME_0] THEN
641 ASM_SIMP_TAC[ARITH_RULE `~(p = 0) ==> 0 < p`] THEN
642 DISCH_TAC THEN REWRITE_TAC[ADD_CLAUSES; GSYM MULT_ASSOC] THEN
643 AP_TERM_TAC THEN UNDISCH_TAC `p divides r` THEN
644 REWRITE_TAC[divides] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
645 ASM_SIMP_TAC[DIV_MULT] THEN REWRITE_TAC[MULT_AC]; ALL_TAC] THEN
646 UNDISCH_TAC `(a EXP m == 1) (mod n)` THEN
647 ASM_SIMP_TAC[CONG] THEN
648 DISCH_THEN(MP_TAC o C AP_THM `r DIV p` o AP_TERM `(EXP)`) THEN
649 DISCH_THEN(MP_TAC o C AP_THM `n:num` o AP_TERM `(MOD)`) THEN
650 ASM_SIMP_TAC[MOD_EXP_MOD] THEN
651 REWRITE_TAC[EXP_EXP; EXP_ONE]);;
653 (* ------------------------------------------------------------------------- *)
654 (* Prime factorizations. *)
655 (* ------------------------------------------------------------------------- *)
657 let primefact = new_definition
658 `primefact ps n <=> (ITLIST (*) ps 1 = n) /\ !p. MEM p ps ==> prime(p)`;;
660 let PRIMEFACT = prove
661 (`!n. ~(n = 0) ==> ?ps. primefact ps n`,
662 MATCH_MP_TAC num_WF THEN X_GEN_TAC `n:num` THEN
663 ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[] THENL
664 [REPEAT DISCH_TAC THEN EXISTS_TAC `[]:num list` THEN
665 REWRITE_TAC[primefact; ITLIST; MEM]; ALL_TAC] THEN
666 DISCH_TAC THEN DISCH_TAC THEN
667 FIRST_ASSUM(X_CHOOSE_THEN `p:num` STRIP_ASSUME_TAC o
668 MATCH_MP PRIME_FACTOR) THEN
669 UNDISCH_TAC `p divides n` THEN REWRITE_TAC[divides] THEN
670 DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST_ALL_TAC) THEN
671 FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
672 UNDISCH_TAC `~(p * m = 0)` THEN
673 ASM_CASES_TAC `m = 0` THEN ASM_REWRITE_TAC[MULT_CLAUSES] THEN DISCH_TAC THEN
674 GEN_REWRITE_TAC (funpow 3 LAND_CONV) [ARITH_RULE `n = 1 * n`] THEN
675 ASM_REWRITE_TAC[LT_MULT_RCANCEL] THEN
676 SUBGOAL_THEN `1 < p` (fun th -> REWRITE_TAC[th]) THENL
677 [MATCH_MP_TAC(ARITH_RULE `~(p = 0) /\ ~(p = 1) ==> 1 < p`) THEN
678 REPEAT STRIP_TAC THEN UNDISCH_TAC `prime p` THEN
679 ASM_REWRITE_TAC[PRIME_0; PRIME_1]; ALL_TAC] THEN
680 REWRITE_TAC[primefact] THEN
681 DISCH_THEN(X_CHOOSE_THEN `ps:num list` ASSUME_TAC) THEN
682 EXISTS_TAC `CONS (p:num) ps` THEN
683 ASM_REWRITE_TAC[MEM; ITLIST] THEN ASM_MESON_TAC[]);;
685 let PRIMAFACT_CONTAINS = prove
686 (`!ps n. primefact ps n ==> !p. prime p /\ p divides n ==> MEM p ps`,
687 REPEAT GEN_TAC THEN REWRITE_TAC[primefact] THEN
688 DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
689 POP_ASSUM(SUBST1_TAC o SYM) THEN
690 SPEC_TAC(`ps:num list`,`ps:num list`) THEN LIST_INDUCT_TAC THEN
691 REWRITE_TAC[ITLIST; MEM] THENL
692 [ASM_MESON_TAC[DIVIDES_ONE; PRIME_1]; ALL_TAC] THEN
693 STRIP_TAC THEN GEN_TAC THEN
694 DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT1 th) THEN MP_TAC th) THEN
695 DISCH_THEN(DISJ_CASES_TAC o MATCH_MP PRIME_DIVPROD) THEN
696 ASM_MESON_TAC[prime; PRIME_1]);;
698 let PRIMEFACT_VARIANT = prove
699 (`!ps n. primefact ps n <=> (ITLIST (*) ps 1 = n) /\ ALL prime ps`,
700 REPEAT GEN_TAC THEN REWRITE_TAC[primefact] THEN AP_TERM_TAC THEN
701 SPEC_TAC(`ps:num list`,`ps:num list`) THEN LIST_INDUCT_TAC THEN
702 ASM_REWRITE_TAC[MEM; ALL] THEN ASM_MESON_TAC[]);;
704 (* ------------------------------------------------------------------------- *)
705 (* Variant of Lucas theorem. *)
706 (* ------------------------------------------------------------------------- *)
708 let LUCAS_PRIMEFACT = prove
710 (a EXP (n - 1) == 1) (mod n) /\
711 (ITLIST (*) ps 1 = n - 1) /\
712 ALL (\p. prime p /\ ~(a EXP ((n - 1) DIV p) == 1) (mod n)) ps
714 REPEAT STRIP_TAC THEN MATCH_MP_TAC LUCAS THEN
715 EXISTS_TAC `a:num` THEN ASM_REWRITE_TAC[] THEN
716 SUBGOAL_THEN `primefact ps (n - 1)` MP_TAC THENL
717 [ASM_REWRITE_TAC[PRIMEFACT_VARIANT] THEN MATCH_MP_TAC ALL_IMP THEN
718 EXISTS_TAC `\p. prime p /\ ~(a EXP ((n - 1) DIV p) == 1) (mod n)` THEN
719 ASM_SIMP_TAC[]; ALL_TAC] THEN
720 DISCH_THEN(ASSUME_TAC o MATCH_MP PRIMAFACT_CONTAINS) THEN
721 X_GEN_TAC `p:num` THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN UNDISCH_TAC
722 `ALL (\p. prime p /\ ~(a EXP ((n - 1) DIV p) == 1) (mod n)) ps` THEN
723 SPEC_TAC(`ps:num list`,`ps:num list`) THEN LIST_INDUCT_TAC THEN
724 SIMP_TAC[ALL; MEM] THEN ASM_MESON_TAC[]);;
726 (* ------------------------------------------------------------------------- *)
727 (* Utility functions. *)
728 (* ------------------------------------------------------------------------- *)
731 mod_num n num_2 =/ num_0;;
733 let odd_num = not o even_num;;
735 (* ------------------------------------------------------------------------- *)
736 (* Least p >= 0 with x <= 2^p. *)
737 (* ------------------------------------------------------------------------- *)
742 else log2 (quo_num x num_2) (y +/ num_1) in
743 fun x -> log2 (x -/ num_1) num_0;;
745 (* ------------------------------------------------------------------------- *)
746 (* Raise number to power (x^m) modulo n. *)
747 (* ------------------------------------------------------------------------- *)
749 let rec powermod x m n =
750 if m =/ num_0 then num_1 else
751 let y = powermod x (quo_num m num_2) n in
752 let z = mod_num (y */ y) n in
753 if even_num m then z else
756 (* ------------------------------------------------------------------------- *)
757 (* Make a call to PARI/GP to factor a number into (probable) primes. *)
758 (* ------------------------------------------------------------------------- *)
761 let suck_file s = let data = string_of_file s in Sys.remove s; data in
762 let extract_output s =
763 let l0 = explode s in
765 let l1 = snd(chop_list(index "]" l0') l0') in
766 let l2 = "["::rev(fst(chop_list(index "[" l1) l1)) in
767 let tm = parse_term (implode l2) in
768 map ((dest_numeral F_F dest_numeral) o dest_pair) (dest_list tm) in
770 if n =/ num_1 then [] else
771 let filename = Filename.temp_file "pocklington" ".out" in
772 let s = "echo 'print(factorint(" ^
774 ")) \n quit' | gp >" ^ filename ^ " 2>/dev/null" in
775 if Sys.command s = 0 then
776 let output = suck_file filename in
777 extract_output output
779 failwith "factor: Call to GP/PARI failed";;
781 (* ------------------------------------------------------------------------- *)
782 (* Alternative giving multiset instead of set plus indices. *)
783 (* ------------------------------------------------------------------------- *)
786 let rec multilist l =
787 if l = [] then [] else
789 replicate x (Num.int_of_num n) @ multilist (tl l) in
790 fun n -> multilist (factor n);;
792 (* ------------------------------------------------------------------------- *)
793 (* Recursive creation of Pratt primality certificates. *)
794 (* ------------------------------------------------------------------------- *)
798 | Primroot_and_factors of
799 ((num * num list) * num * (num * certificate) list);;
801 let find_primitive_root =
802 let rec find_primitive_root a m ms n =
803 if gcd_num a n =/ num_1 &
804 powermod a m n =/ num_1 &
805 forall (fun k -> powermod a k n <>/ num_1) ms
807 else find_primitive_root (a +/ num_1) m ms n in
808 let find_primitive_root_from_2 = find_primitive_root num_2 in
810 if n </ num_2 then failwith "find_primitive_root: input too small"
811 else find_primitive_root_from_2 m ms n;;
816 [] -> raise Unchanged
817 | (h::t) -> if x =/ h then
820 else x::(uniq h t) in
821 fun l -> if l = [] then [] else uniq (hd l) (tl l);;
824 let s' = sort (<=/) s in
825 try uniq_num s' with Unchanged -> s';;
828 let rec cert_prime n =
830 if n =/ num_2 then Prime_2
831 else failwith "certify_prime: not a prime!"
833 let m = n -/ num_1 in
834 let pfact = multifactor m in
835 let primes = setify_num pfact in
836 let ms = map (fun d -> div_num m d) primes in
837 let a = find_primitive_root m ms n in
838 Primroot_and_factors((n,pfact),a,map (fun n -> n,cert_prime n) primes) in
839 fun n -> if length(multifactor n) = 1 then cert_prime n
840 else failwith "certify_prime: input is not a prime";;
842 (* ------------------------------------------------------------------------- *)
843 (* Relatively efficient evaluation of "(a EXP m == 1) (mod n)". *)
844 (* ------------------------------------------------------------------------- *)
846 let EXP_EQ_MOD_CONV =
849 ==> ((a EXP 0) MOD n = 1 MOD n) /\
850 ((a EXP (NUMERAL (BIT0 m))) MOD n =
851 let b = (a EXP (NUMERAL m)) MOD n in
853 ((a EXP (NUMERAL (BIT1 m))) MOD n =
854 let b = (a EXP (NUMERAL m)) MOD n in
855 (a * ((b * b) MOD n)) MOD n)`,
856 DISCH_TAC THEN REWRITE_TAC[EXP] THEN
857 REWRITE_TAC[NUMERAL; BIT0; BIT1] THEN
858 REWRITE_TAC[EXP; EXP_ADD] THEN
859 CONV_TAC(ONCE_DEPTH_CONV let_CONV) THEN
860 ASM_SIMP_TAC[MOD_MULT_LMOD; MOD_MULT_RMOD] THEN
861 REWRITE_TAC[MULT_ASSOC] THEN
862 ASM_SIMP_TAC[MOD_MULT_LMOD; MOD_MULT_RMOD] THEN
863 ONCE_REWRITE_TAC[MULT_SYM] THEN
864 REWRITE_TAC[MULT_ASSOC] THEN
865 ASM_SIMP_TAC[MOD_MULT_LMOD; MOD_MULT_RMOD])
866 and pth_cong = SPEC_ALL CONG
867 and n_tm = `n:num` in
869 let ntm = rand(rand tm) in
870 let th1 = INST [ntm,n_tm] pth_cong in
871 let th2 = EQF_ELIM(NUM_EQ_CONV(rand(lhand(concl th1)))) in
872 let th3 = REWR_CONV (MP th1 th2) tm in
873 let th4 = MP (INST [ntm,n_tm] pth) th2 in
874 let th4a,th4b = CONJ_PAIR th4 in
875 let conv_base = GEN_REWRITE_CONV I [th4a]
876 and conv_step = GEN_REWRITE_CONV I [th4b] in
878 try conv_base tm with Failure _ ->
882 NUM_REDUCE_CONV) tm in
883 let th5 = (LAND_CONV conv THENC NUM_REDUCE_CONV) (rand(concl th3)) in
885 let gconv_net = itlist (uncurry net_of_conv)
886 [`(a EXP m == 1) (mod n)`,raw_conv] empty_net in
887 REWRITES_CONV gconv_net;;
889 (* ------------------------------------------------------------------------- *)
890 (* HOL checking of such a certificate. We retain a cache for efficiency. *)
891 (* ------------------------------------------------------------------------- *)
893 let prime_theorem_cache = ref [];;
895 let rec lookup_under_num n l =
896 if l = [] then failwith "lookup_under_num" else
898 if fst h =/ n then snd h
899 else lookup_under_num n (tl l);;
901 let check_certificate =
904 and ps_tm = `ps:num list`
905 and SIMPLE_REWRITE_CONV = REWRITE_CONV[]
906 and CONJ_AC_SORTED = TAUT `(a /\ a /\ b <=> a /\ b) /\ (a /\ a <=> a)` in
907 let CLEAN_RULE = CONV_RULE
908 (REWRITE_CONV[ITLIST; ALL; CONJ_AC_SORTED] THENC
909 ONCE_DEPTH_CONV NUM_SUB_CONV THENC
910 DEPTH_CONV NUM_MULT_CONV THENC
911 ONCE_DEPTH_CONV NUM_DIV_CONV THENC
912 ONCE_DEPTH_CONV(NUM_EQ_CONV ORELSEC NUM_LE_CONV) THENC
913 SIMPLE_REWRITE_CONV) in
914 let rec check_certificate cert =
918 | Primroot_and_factors((n,ps),a,ncerts) ->
919 try lookup_under_num n (!prime_theorem_cache) with Failure _ ->
920 let th1 = INST [mk_numeral n,n_tm;
921 mk_flist (map mk_numeral ps),ps_tm;
924 let th2 = CLEAN_RULE th1 in
925 let th3 = ONCE_DEPTH_CONV EXP_EQ_MOD_CONV (concl th2) in
926 let th4 = CONV_RULE SIMPLE_REWRITE_CONV (EQ_MP th3 th2) in
927 let ants = conjuncts(lhand(concl th4)) in
929 map (fun t -> lookup_under_num (dest_numeral(rand t)) ncerts)
931 let ths = map check_certificate certs in
932 let fth = MP th4 (end_itlist CONJ ths) in
933 prime_theorem_cache := (n,fth)::(!prime_theorem_cache); fth in
936 (* ------------------------------------------------------------------------- *)
937 (* Hence a primality-proving rule. *)
938 (* ------------------------------------------------------------------------- *)
940 let PROVE_PRIME = check_certificate o certify_prime;;
942 (* ------------------------------------------------------------------------- *)
943 (* Rule to generate prime factorization theorems. *)
944 (* ------------------------------------------------------------------------- *)
946 let PROVE_PRIMEFACT =
947 let pth = SPEC_ALL PRIMEFACT_VARIANT
948 and start_CONV = PURE_REWRITE_CONV[ITLIST; ALL] THENC NUM_REDUCE_CONV
949 and ps_tm = `ps:num list`
950 and n_tm = `n:num` in
952 let pfact = multifactor n in
953 let th1 = INST [mk_flist(map mk_numeral pfact),ps_tm;
954 mk_numeral n,n_tm] pth in
955 let th2 = TRANS th1 (start_CONV(rand(concl th1))) in
956 let ths = map PROVE_PRIME pfact in
957 EQ_MP (SYM th2) (end_itlist CONJ ths);;
959 (* ------------------------------------------------------------------------- *)
960 (* Conversion for truth or falsity of primality assertion. *)
961 (* ------------------------------------------------------------------------- *)
964 let NOT_PRIME_THM = prove
965 (`((m = 1) <=> F) ==> ((m = p) <=> F) ==> (m * n = p) ==> (prime(p) <=> F)`,
966 MESON_TAC[prime; divides])
967 and m_tm = `m:num` and n_tm = `n:num` and p_tm = `p:num` in
969 let p = dest_numeral tm in
970 if p =/ Int 0 then EQF_INTRO PRIME_0
971 else if p =/ Int 1 then EQF_INTRO PRIME_1 else
972 let pfact = multifactor p in
973 if length pfact = 1 then
974 (remark ("proving that " ^ string_of_num p ^ " is prime");
975 EQT_INTRO(PROVE_PRIME p))
977 (remark ("proving that " ^ string_of_num p ^ " is composite");
978 let m = hd pfact and n = end_itlist ( */ ) (tl pfact) in
979 let th0 = INST [mk_numeral m,m_tm; mk_numeral n,n_tm; mk_numeral p,p_tm]
981 let th1 = MP th0 (NUM_EQ_CONV (lhand(lhand(concl th0)))) in
982 let th2 = MP th1 (NUM_EQ_CONV (lhand(lhand(concl th1)))) in
983 MP th2 (NUM_MULT_CONV(lhand(lhand(concl th2)))));;
986 let prime_tm = `prime` in
988 let ptm,tm = dest_comb tm0 in
989 if ptm <> prime_tm then failwith "expected term of form prime(n)"
992 (* ------------------------------------------------------------------------- *)
994 (* ------------------------------------------------------------------------- *)
996 map (time PRIME_TEST o mk_small_numeral) (0--50);;
998 time PRIME_TEST `65535`;;
1000 time PRIME_TEST `65536`;;
1002 time PRIME_TEST `65537`;;
1004 time PROVE_PRIMEFACT (Int 222);;
1006 time PROVE_PRIMEFACT (Int 151);;
1008 (* ------------------------------------------------------------------------- *)
1009 (* The "Landau trick" in Erdos's proof of Chebyshev-Bertrand theorem. *)
1010 (* ------------------------------------------------------------------------- *)
1012 map (time PRIME_TEST o mk_small_numeral)
1013 [3; 5; 7; 13; 23; 43; 83; 163; 317; 631; 1259; 2503; 4001];;