wenzelm@11049: (* Title: HOL/NumberTheory/WilsonRuss.thy paulson@9508: ID: $Id$ wenzelm@11049: Author: Thomas M. Rasmussen wenzelm@11049: Copyright 2000 University of Cambridge paulson@9508: *) paulson@9508: wenzelm@11049: header {* Wilson's Theorem according to Russinoff *} wenzelm@11049: haftmann@16417: theory WilsonRuss imports EulerFermat 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@19670: definition wenzelm@21404: inv :: "int => int => int" where wenzelm@19670: "inv p a = (a^(nat (p - 2))) mod p" wenzelm@19670: paulson@9508: consts wenzelm@11049: wset :: "int * int => int set" paulson@9508: wenzelm@11049: recdef wset wenzelm@11049: "measure ((\(a, p). nat a) :: int * int => nat)" wenzelm@11049: "wset (a, p) = paulson@11868: (if 1 < a then paulson@11868: 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)" paulson@13833: 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) wenzelm@11049: apply (subst zmod_zmult1_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) paulson@11868: apply (subgoal_tac "\ p dvd 1") wenzelm@11049: apply (rule_tac [2] zdvd_not_zless) paulson@11868: apply (subgoal_tac "p dvd 1") wenzelm@11049: prefer 2 paulson@13833: apply (subst zdvd_zminus_iff [symmetric], 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) obua@14738: apply (simp add: OrderedGroup.diff_diff_eq diff_diff_eq2 zdiff_zmult_distrib2) paulson@11868: apply (rule_tac s = "p dvd -((a + 1) + (p * -a))" in trans) paulson@14271: apply (simp add: mult_commute) wenzelm@11049: apply (subst zdvd_zminus_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]) wenzelm@11049: apply (simp add: zmult_int [symmetric]) wenzelm@11049: apply (simp add: zdiff_zmult_distrib zdiff_zmult_distrib2) 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) wenzelm@11049: apply (auto simp add: zpower_zadd_distrib) 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) wenzelm@11049: apply (subst zpower_zmod) 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] paulson@11868: "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) \ wenzelm@19670: P (wset (a - 1, p)) (a - 1) p ==> P (wset (a, p)) a p" wenzelm@18369: shows "P (wset (u, v)) u v" wenzelm@18369: apply (rule wset.induct, safe) wenzelm@18369: prefer 2 wenzelm@18369: apply (case_tac "1 < a") wenzelm@18369: apply (rule prems) wenzelm@18369: apply simp_all wenzelm@18369: apply (simp_all add: wset.simps prems) wenzelm@18369: done wenzelm@11049: wenzelm@11049: lemma wset_mem_imp_or [rule_format]: paulson@11868: "1 < a \ b \ wset (a - 1, p) wenzelm@11049: ==> 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: paulson@11868: 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: paulson@11868: 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]: nipkow@16663: "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]: nipkow@16663: "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 --> paulson@11868: 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]: nipkow@16663: "zprime p --> 5 \ p --> a < p - 1 --> b \ wset (a, p) wenzelm@11049: --> 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 wenzelm@11049: \ 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: wenzelm@11049: 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 --> nipkow@15392: 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) paulson@13833: apply (unfold Let_def, auto) wenzelm@11049: apply (subst setprod_insert) wenzelm@11049: apply (tactic {* stac (thm "setprod_insert") 3 *}) wenzelm@11049: apply (subgoal_tac [5] nipkow@15392: "zcong (a * inv p a * (\x\ wset(a - 1, p). x)) (1 * 1) p") wenzelm@11049: prefer 5 wenzelm@11049: apply (simp add: zmult_assoc) wenzelm@11049: apply (rule_tac [5] zcong_zmult) wenzelm@11049: apply (rule_tac [5] inv_is_inv) wenzelm@11049: apply (tactic "Clarify_tac 4") paulson@11868: 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: nipkow@16663: 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