wenzelm@38159: (* Title: HOL/Old_Number_Theory/WilsonRuss.thy wenzelm@38159: Author: Thomas M. Rasmussen wenzelm@11049: Copyright 2000 University of Cambridge paulson@9508: *) paulson@9508: wenzelm@58889: section {* Wilson's Theorem according to Russinoff *} wenzelm@11049: wenzelm@38159: theory WilsonRuss wenzelm@38159: imports EulerFermat wenzelm@38159: begin wenzelm@11049: wenzelm@11049: text {* wenzelm@11049: Wilson's Theorem following quite closely Russinoff's approach wenzelm@11049: using Boyer-Moore (using finite sets instead of lists, though). wenzelm@11049: *} wenzelm@11049: wenzelm@11049: subsection {* Definitions and lemmas *} paulson@9508: wenzelm@38159: definition inv :: "int => int => int" wenzelm@38159: where "inv p a = (a^(nat (p - 2))) mod p" wenzelm@19670: wenzelm@38159: fun wset :: "int \ int => int set" where krauss@35440: "wset a p = paulson@11868: (if 1 < a then krauss@35440: let ws = wset (a - 1) p wenzelm@11049: in (if a \ ws then ws else insert a (insert (inv p a) ws)) else {})" wenzelm@11049: wenzelm@11049: wenzelm@11049: text {* \medskip @{term [source] inv} *} wenzelm@11049: wenzelm@13524: lemma inv_is_inv_aux: "1 < m ==> Suc (nat (m - 2)) = nat (m - 1)" wenzelm@38159: by (subst int_int_eq [symmetric]) auto wenzelm@11049: wenzelm@11049: lemma inv_is_inv: nipkow@16663: "zprime p \ 0 < a \ a < p ==> [a * inv p a = 1] (mod p)" wenzelm@11049: apply (unfold inv_def) wenzelm@11049: apply (subst zcong_zmod) huffman@47163: apply (subst mod_mult_right_eq [symmetric]) wenzelm@11049: apply (subst zcong_zmod [symmetric]) wenzelm@11049: apply (subst power_Suc [symmetric]) wenzelm@13524: apply (subst inv_is_inv_aux) wenzelm@11049: apply (erule_tac [2] Little_Fermat) wenzelm@11049: apply (erule_tac [2] zdvd_not_zless) paulson@13833: apply (unfold zprime_def, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_distinct: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> a \ inv p a" wenzelm@11049: apply safe wenzelm@11049: apply (cut_tac a = a and p = p in zcong_square) paulson@13833: apply (cut_tac [3] a = a and p = p in inv_is_inv, auto) paulson@11868: apply (subgoal_tac "a = 1") wenzelm@11049: apply (rule_tac [2] m = p in zcong_zless_imp_eq) paulson@11868: apply (subgoal_tac [7] "a = p - 1") paulson@13833: apply (rule_tac [8] m = p in zcong_zless_imp_eq, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_not_0: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> inv p a \ 0" wenzelm@11049: apply safe wenzelm@11049: apply (cut_tac a = a and p = p in inv_is_inv) paulson@13833: apply (unfold zcong_def, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_not_1: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> inv p a \ 1" wenzelm@11049: apply safe wenzelm@11049: apply (cut_tac a = a and p = p in inv_is_inv) wenzelm@11049: prefer 4 wenzelm@11049: apply simp paulson@11868: apply (subgoal_tac "a = 1") paulson@13833: apply (rule_tac [2] zcong_zless_imp_eq, auto) wenzelm@11049: done wenzelm@11049: wenzelm@19670: lemma inv_not_p_minus_1_aux: wenzelm@19670: "[a * (p - 1) = 1] (mod p) = [a = p - 1] (mod p)" wenzelm@11049: apply (unfold zcong_def) huffman@44766: apply (simp add: diff_diff_eq diff_diff_eq2 right_diff_distrib) paulson@11868: apply (rule_tac s = "p dvd -((a + 1) + (p * -a))" in trans) haftmann@35048: apply (simp add: algebra_simps) nipkow@30042: apply (subst dvd_minus_iff) wenzelm@11049: apply (subst zdvd_reduce) paulson@11868: apply (rule_tac s = "p dvd (a + 1) + (p * -1)" in trans) paulson@13833: apply (subst zdvd_reduce, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_not_p_minus_1: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> inv p a \ p - 1" wenzelm@11049: apply safe paulson@13833: apply (cut_tac a = a and p = p in inv_is_inv, auto) wenzelm@13524: apply (simp add: inv_not_p_minus_1_aux) paulson@11868: apply (subgoal_tac "a = p - 1") paulson@13833: apply (rule_tac [2] zcong_zless_imp_eq, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_g_1: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> 1 < inv p a" paulson@11868: apply (case_tac "0\ inv p a") paulson@11868: apply (subgoal_tac "inv p a \ 1") paulson@11868: apply (subgoal_tac "inv p a \ 0") wenzelm@11049: apply (subst order_less_le) wenzelm@11049: apply (subst zle_add1_eq_le [symmetric]) wenzelm@11049: apply (subst order_less_le) wenzelm@11049: apply (rule_tac [2] inv_not_0) paulson@13833: apply (rule_tac [5] inv_not_1, auto) paulson@13833: apply (unfold inv_def zprime_def, simp) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma inv_less_p_minus_1: nipkow@16663: "zprime p \ 1 < a \ a < p - 1 ==> inv p a < p - 1" wenzelm@11049: apply (case_tac "inv p a < p") wenzelm@11049: apply (subst order_less_le) paulson@13833: apply (simp add: inv_not_p_minus_1, auto) paulson@13833: apply (unfold inv_def zprime_def, simp) wenzelm@11049: done wenzelm@11049: wenzelm@13524: lemma inv_inv_aux: "5 \ p ==> paulson@11868: nat (p - 2) * nat (p - 2) = Suc (nat (p - 1) * nat (p - 3))" wenzelm@11049: apply (subst int_int_eq [symmetric]) huffman@44821: apply (simp add: of_nat_mult) huffman@44766: apply (simp add: left_diff_distrib right_diff_distrib) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma zcong_zpower_zmult: paulson@11868: "[x^y = 1] (mod p) \ [x^(y * z) = 1] (mod p)" wenzelm@11049: apply (induct z) huffman@44766: apply (auto simp add: power_add) nipkow@15236: apply (subgoal_tac "zcong (x^y * x^(y * z)) (1 * 1) p") paulson@13833: apply (rule_tac [2] zcong_zmult, simp_all) wenzelm@11049: done wenzelm@11049: nipkow@16663: lemma inv_inv: "zprime p \ paulson@11868: 5 \ p \ 0 < a \ a < p ==> inv p (inv p a) = a" wenzelm@11049: apply (unfold inv_def) huffman@47164: apply (subst power_mod) wenzelm@11049: apply (subst zpower_zpower) wenzelm@11049: apply (rule zcong_zless_imp_eq) wenzelm@11049: prefer 5 wenzelm@11049: apply (subst zcong_zmod) wenzelm@11049: apply (subst mod_mod_trivial) wenzelm@11049: apply (subst zcong_zmod [symmetric]) wenzelm@13524: apply (subst inv_inv_aux) wenzelm@11049: apply (subgoal_tac [2] wenzelm@32960: "zcong (a * a^(nat (p - 1) * nat (p - 3))) (a * 1) p") wenzelm@11049: apply (rule_tac [3] zcong_zmult) wenzelm@11049: apply (rule_tac [4] zcong_zpower_zmult) wenzelm@11049: apply (erule_tac [4] Little_Fermat) paulson@13833: apply (rule_tac [4] zdvd_not_zless, simp_all) wenzelm@11049: done wenzelm@11049: wenzelm@11049: wenzelm@11049: text {* \medskip @{term wset} *} wenzelm@11049: wenzelm@11049: declare wset.simps [simp del] paulson@9508: wenzelm@11049: lemma wset_induct: wenzelm@18369: assumes "!!a p. P {} a p" wenzelm@19670: and "!!a p. 1 < (a::int) \ krauss@35440: P (wset (a - 1) p) (a - 1) p ==> P (wset a p) a p" krauss@35440: shows "P (wset u v) u v" krauss@35440: apply (rule wset.induct) krauss@35440: apply (case_tac "1 < a") krauss@35440: apply (rule assms) krauss@35440: apply (simp_all add: wset.simps assms) wenzelm@18369: done wenzelm@11049: wenzelm@11049: lemma wset_mem_imp_or [rule_format]: krauss@35440: "1 < a \ b \ wset (a - 1) p krauss@35440: ==> b \ wset a p --> b = a \ b = inv p a" wenzelm@11049: apply (subst wset.simps) paulson@13833: apply (unfold Let_def, simp) wenzelm@11049: done wenzelm@11049: krauss@35440: lemma wset_mem_mem [simp]: "1 < a ==> a \ wset a p" wenzelm@11049: apply (subst wset.simps) paulson@13833: apply (unfold Let_def, simp) wenzelm@11049: done wenzelm@11049: krauss@35440: lemma wset_subset: "1 < a \ b \ wset (a - 1) p ==> b \ wset a p" wenzelm@11049: apply (subst wset.simps) paulson@13833: apply (unfold Let_def, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_g_1 [rule_format]: krauss@35440: "zprime p --> a < p - 1 --> b \ wset a p --> 1 < b" paulson@13833: apply (induct a p rule: wset_induct, auto) wenzelm@11049: apply (case_tac "b = a") wenzelm@11049: apply (case_tac [2] "b = inv p a") wenzelm@11049: apply (subgoal_tac [3] "b = a \ b = inv p a") wenzelm@11049: apply (rule_tac [4] wset_mem_imp_or) wenzelm@11049: prefer 2 wenzelm@11049: apply simp paulson@13833: apply (rule inv_g_1, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_less [rule_format]: krauss@35440: "zprime p --> a < p - 1 --> b \ wset a p --> b < p - 1" paulson@13833: apply (induct a p rule: wset_induct, auto) wenzelm@11049: apply (case_tac "b = a") wenzelm@11049: apply (case_tac [2] "b = inv p a") wenzelm@11049: apply (subgoal_tac [3] "b = a \ b = inv p a") wenzelm@11049: apply (rule_tac [4] wset_mem_imp_or) wenzelm@11049: prefer 2 wenzelm@11049: apply simp paulson@13833: apply (rule inv_less_p_minus_1, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_mem [rule_format]: nipkow@16663: "zprime p --> krauss@35440: a < p - 1 --> 1 < b --> b \ a --> b \ wset a p" paulson@13833: apply (induct a p rule: wset.induct, auto) nipkow@15197: apply (rule_tac wset_subset) nipkow@15197: apply (simp (no_asm_simp)) nipkow@15197: apply auto wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_mem_inv_mem [rule_format]: krauss@35440: "zprime p --> 5 \ p --> a < p - 1 --> b \ wset a p krauss@35440: --> inv p b \ wset a p" paulson@13833: apply (induct a p rule: wset_induct, auto) wenzelm@11049: apply (case_tac "b = a") wenzelm@11049: apply (subst wset.simps) wenzelm@11049: apply (unfold Let_def) paulson@13833: apply (rule_tac [3] wset_subset, auto) wenzelm@11049: apply (case_tac "b = inv p a") wenzelm@11049: apply (simp (no_asm_simp)) wenzelm@11049: apply (subst inv_inv) wenzelm@11049: apply (subgoal_tac [6] "b = a \ b = inv p a") paulson@13833: apply (rule_tac [7] wset_mem_imp_or, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_inv_mem_mem: nipkow@16663: "zprime p \ 5 \ p \ a < p - 1 \ 1 < b \ b < p - 1 krauss@35440: \ inv p b \ wset a p \ b \ wset a p" wenzelm@11049: apply (rule_tac s = "inv p (inv p b)" and t = b in subst) wenzelm@11049: apply (rule_tac [2] wset_mem_inv_mem) paulson@13833: apply (rule inv_inv, simp_all) wenzelm@11049: done wenzelm@11049: krauss@35440: lemma wset_fin: "finite (wset a p)" wenzelm@11049: apply (induct a p rule: wset_induct) wenzelm@11049: prefer 2 wenzelm@11049: apply (subst wset.simps) paulson@13833: apply (unfold Let_def, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: lemma wset_zcong_prod_1 [rule_format]: nipkow@16663: "zprime p --> krauss@35440: 5 \ p --> a < p - 1 --> [(\x\wset a p. x) = 1] (mod p)" wenzelm@11049: apply (induct a p rule: wset_induct) wenzelm@11049: prefer 2 wenzelm@11049: apply (subst wset.simps) krauss@35440: apply (auto, unfold Let_def, auto) haftmann@57418: apply (subst setprod.insert) haftmann@57418: apply (tactic {* stac @{thm setprod.insert} 3 *}) wenzelm@11049: apply (subgoal_tac [5] krauss@35440: "zcong (a * inv p a * (\x\wset (a - 1) p. x)) (1 * 1) p") wenzelm@11049: prefer 5 haftmann@57512: apply (simp add: mult.assoc) wenzelm@11049: apply (rule_tac [5] zcong_zmult) wenzelm@11049: apply (rule_tac [5] inv_is_inv) wenzelm@42793: apply (tactic "clarify_tac @{context} 4") krauss@35440: apply (subgoal_tac [4] "a \ wset (a - 1) p") wenzelm@11049: apply (rule_tac [5] wset_inv_mem_mem) wenzelm@11049: apply (simp_all add: wset_fin) paulson@13833: apply (rule inv_distinct, auto) wenzelm@11049: done wenzelm@11049: krauss@35440: lemma d22set_eq_wset: "zprime p ==> d22set (p - 2) = wset (p - 2) p" wenzelm@11049: apply safe wenzelm@11049: apply (erule wset_mem) wenzelm@11049: apply (rule_tac [2] d22set_g_1) wenzelm@11049: apply (rule_tac [3] d22set_le) wenzelm@11049: apply (rule_tac [4] d22set_mem) wenzelm@11049: apply (erule_tac [4] wset_g_1) wenzelm@11049: prefer 6 wenzelm@11049: apply (subst zle_add1_eq_le [symmetric]) paulson@11868: apply (subgoal_tac "p - 2 + 1 = p - 1") wenzelm@11049: apply (simp (no_asm_simp)) paulson@13833: apply (erule wset_less, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: wenzelm@11049: subsection {* Wilson *} wenzelm@11049: nipkow@16663: lemma prime_g_5: "zprime p \ p \ 2 \ p \ 3 ==> 5 \ p" wenzelm@11049: apply (unfold zprime_def dvd_def) paulson@13833: apply (case_tac "p = 4", auto) wenzelm@11049: apply (rule notE) wenzelm@11049: prefer 2 wenzelm@11049: apply assumption wenzelm@11049: apply (simp (no_asm)) paulson@13833: apply (rule_tac x = 2 in exI) paulson@13833: apply (safe, arith) paulson@13833: apply (rule_tac x = 2 in exI, auto) wenzelm@11049: done wenzelm@11049: wenzelm@11049: theorem Wilson_Russ: nipkow@16663: "zprime p ==> [zfact (p - 1) = -1] (mod p)" paulson@11868: apply (subgoal_tac "[(p - 1) * zfact (p - 2) = -1 * 1] (mod p)") wenzelm@11049: apply (rule_tac [2] zcong_zmult) wenzelm@11049: apply (simp only: zprime_def) wenzelm@11049: apply (subst zfact.simps) paulson@13833: apply (rule_tac t = "p - 1 - 1" and s = "p - 2" in subst, auto) wenzelm@11049: apply (simp only: zcong_def) wenzelm@11049: apply (simp (no_asm_simp)) wenzelm@11704: apply (case_tac "p = 2") wenzelm@11049: apply (simp add: zfact.simps) wenzelm@11704: apply (case_tac "p = 3") wenzelm@11049: apply (simp add: zfact.simps) wenzelm@11704: apply (subgoal_tac "5 \ p") wenzelm@11049: apply (erule_tac [2] prime_g_5) wenzelm@11049: apply (subst d22set_prod_zfact [symmetric]) wenzelm@11049: apply (subst d22set_eq_wset) paulson@13833: apply (rule_tac [2] wset_zcong_prod_1, auto) wenzelm@11049: done paulson@9508: paulson@9508: end