Removed Old_Number_Theory; all theories ported (thanks to Jaime Mendizabal Roche)
authoreberlm <eberlm@in.tum.de>
Mon Oct 17 15:20:06 2016 +0200 (2016-10-17)
changeset 64282261d42f0bfac
parent 64281 bfc2e92d9b4c
child 64283 979cdfdf7a79
Removed Old_Number_Theory; all theories ported (thanks to Jaime Mendizabal Roche)
src/HOL/Number_Theory/Euler_Criterion.thy
src/HOL/Number_Theory/Gauss.thy
src/HOL/Number_Theory/Number_Theory.thy
src/HOL/Number_Theory/Pocklington.thy
src/HOL/Number_Theory/QuadraticReciprocity.thy
src/HOL/Number_Theory/Residues.thy
src/HOL/Old_Number_Theory/BijectionRel.thy
src/HOL/Old_Number_Theory/Chinese.thy
src/HOL/Old_Number_Theory/Euler.thy
src/HOL/Old_Number_Theory/EulerFermat.thy
src/HOL/Old_Number_Theory/EvenOdd.thy
src/HOL/Old_Number_Theory/Factorization.thy
src/HOL/Old_Number_Theory/Fib.thy
src/HOL/Old_Number_Theory/Finite2.thy
src/HOL/Old_Number_Theory/Gauss.thy
src/HOL/Old_Number_Theory/Int2.thy
src/HOL/Old_Number_Theory/IntFact.thy
src/HOL/Old_Number_Theory/IntPrimes.thy
src/HOL/Old_Number_Theory/Legacy_GCD.thy
src/HOL/Old_Number_Theory/Pocklington.thy
src/HOL/Old_Number_Theory/Primes.thy
src/HOL/Old_Number_Theory/Quadratic_Reciprocity.thy
src/HOL/Old_Number_Theory/Residues.thy
src/HOL/Old_Number_Theory/WilsonBij.thy
src/HOL/Old_Number_Theory/WilsonRuss.thy
src/HOL/Old_Number_Theory/document/root.bib
src/HOL/Old_Number_Theory/document/root.tex
src/HOL/ROOT
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/HOL/Number_Theory/Euler_Criterion.thy	Mon Oct 17 15:20:06 2016 +0200
     1.3 @@ -0,0 +1,171 @@
     1.4 +(* Author: Jaime Mendizabal Roche *)
     1.5 +
     1.6 +theory Euler_Criterion
     1.7 +imports Residues
     1.8 +begin
     1.9 +
    1.10 +context
    1.11 +  fixes p :: "nat"
    1.12 +  fixes a :: "int"
    1.13 +
    1.14 +  assumes p_prime: "prime p"
    1.15 +  assumes p_ge_2: "2 < p"
    1.16 +  assumes p_a_relprime: "[a \<noteq> 0](mod p)"
    1.17 +begin
    1.18 +
    1.19 +private lemma odd_p: "odd p" using p_ge_2 p_prime prime_odd_nat by blast
    1.20 +
    1.21 +private lemma p_minus_1_int: "int (p - 1) = int p - 1" using p_prime prime_ge_1_nat by force
    1.22 +
    1.23 +private lemma E_1: assumes "QuadRes p a"
    1.24 +  shows "[a ^ ((p - 1) div 2) = 1] (mod (int p))"
    1.25 +proof -
    1.26 +  from assms obtain b where b: "[b ^ 2 = a] (mod p)" unfolding QuadRes_def by blast
    1.27 +  hence "[a ^ ((p - 1) div 2) = b ^ (2 * ((p - 1) div 2))] (mod p)"
    1.28 +    by (simp add: cong_exp_int cong_sym_int power_mult)
    1.29 +  hence "[a ^ ((p - 1) div 2) = b ^ (p - 1)] (mod p)" using odd_p by force
    1.30 +  moreover have "~ p dvd b"
    1.31 +    using b cong_altdef_int[of a 0 p] cong_dvd_eq_int[of "b ^ 2" a "int p"] p_a_relprime p_prime
    1.32 +    by (auto simp: prime_dvd_power_int_iff)
    1.33 +  ultimately show ?thesis using fermat_theorem[of p b] p_prime 
    1.34 +    by (auto intro: cong_trans_int)
    1.35 +qed
    1.36 +
    1.37 +private definition S1 :: "int set" where "S1 = {0 <.. int p - 1}"
    1.38 +
    1.39 +private definition P :: "int \<Rightarrow> int \<Rightarrow> bool" where
    1.40 +  "P x y \<longleftrightarrow> [x * y = a] (mod p) \<and> y \<in> S1"
    1.41 +
    1.42 +private definition f_1 :: "int \<Rightarrow> int" where
    1.43 +  "f_1 x = (THE y. P x y)"
    1.44 +
    1.45 +private definition f :: "int \<Rightarrow> int set" where
    1.46 +  "f x = {x, f_1 x}"
    1.47 +
    1.48 +private definition S2 :: "int set set" where "S2 = f ` S1"
    1.49 +
    1.50 +private lemma P_lemma: assumes "x \<in> S1"
    1.51 +  shows "\<exists>! y. P x y"
    1.52 +proof -
    1.53 +  have "~ p dvd x" using assms zdvd_not_zless S1_def by auto
    1.54 +  hence co_xp: "coprime x p" using p_prime prime_imp_coprime_int[of p x] 
    1.55 +    by (simp add: gcd.commute)
    1.56 +  then obtain y' where y': "[x * y' = 1] (mod p)" using cong_solve_coprime_int by blast
    1.57 +  moreover define y where "y = y' * a mod p"
    1.58 +  ultimately have "[x * y = a] (mod p)" using mod_mult_right_eq[of x "y' * a" p]
    1.59 +    cong_scalar_int[of "x * y'"] unfolding cong_int_def mult.assoc by auto
    1.60 +  moreover have "y \<in> {0 .. int p - 1}" unfolding y_def using p_ge_2 by auto
    1.61 +  hence "y \<in> S1" using calculation cong_altdef_int p_a_relprime S1_def by auto
    1.62 +  ultimately have "P x y" unfolding P_def by blast
    1.63 +  moreover {
    1.64 +    fix y1 y2
    1.65 +    assume "P x y1" "P x y2"
    1.66 +    moreover hence "[y1 = y2] (mod p)" unfolding P_def
    1.67 +      using co_xp cong_mult_lcancel_int[of x p y1 y2] cong_sym_int cong_trans_int by blast
    1.68 +    ultimately have "y1 = y2" unfolding P_def S1_def using cong_less_imp_eq_int by auto
    1.69 +  }
    1.70 +  ultimately show ?thesis by blast
    1.71 +qed
    1.72 +
    1.73 +private lemma f_1_lemma_1: assumes "x \<in> S1"
    1.74 +  shows "P x (f_1 x)" using assms P_lemma theI'[of "P x"] f_1_def by presburger
    1.75 +
    1.76 +private lemma f_1_lemma_2: assumes "x \<in> S1"
    1.77 +  shows "f_1 (f_1 x) = x"
    1.78 +  using assms f_1_lemma_1[of x] f_1_def P_lemma[of "f_1 x"] P_def by (auto simp: mult.commute)
    1.79 +
    1.80 +private lemma f_lemma_1: assumes "x \<in> S1"
    1.81 +  shows "f x = f (f_1 x)" using f_def f_1_lemma_2[of x] assms by auto
    1.82 +
    1.83 +private lemma l1: assumes "~ QuadRes p a" "x \<in> S1"
    1.84 +  shows "x \<noteq> f_1 x"
    1.85 +  using f_1_lemma_1[of x] assms unfolding P_def QuadRes_def power2_eq_square by fastforce
    1.86 +
    1.87 +private lemma l2: assumes "~ QuadRes p a" "x \<in> S1"
    1.88 +  shows "[\<Prod> (f x) = a] (mod p)"
    1.89 +  using assms l1 f_1_lemma_1 P_def f_def by auto
    1.90 +
    1.91 +private lemma l3: assumes "x \<in> S2"
    1.92 +  shows "finite x" using assms f_def S2_def by auto
    1.93 +
    1.94 +private lemma l4: "S1 = \<Union> S2" using f_1_lemma_1 P_def f_def S2_def by auto
    1.95 +
    1.96 +private lemma l5: assumes "x \<in> S2" "y \<in> S2" "x \<noteq> y"
    1.97 +  shows "x \<inter> y = {}"
    1.98 +proof -
    1.99 +  obtain a b where ab: "x = f a" "a \<in> S1" "y = f b" "b \<in> S1" using assms S2_def by auto
   1.100 +  hence "a \<noteq> b" "a \<noteq> f_1 b" "f_1 a \<noteq> b" using assms(3) f_lemma_1 by blast+
   1.101 +  moreover hence "f_1 a \<noteq> f_1 b" using f_1_lemma_2[of a] f_1_lemma_2[of b] ab by force
   1.102 +  ultimately show ?thesis using f_def ab by fastforce
   1.103 +qed
   1.104 +
   1.105 +private lemma l6: "prod Prod S2 = \<Prod> S1" 
   1.106 +  using prod.Union_disjoint[of S2 "\<lambda>x. x"] l3 l4 l5 unfolding comp_def by auto
   1.107 +
   1.108 +private lemma l7: "fact n = \<Prod> {0 <.. int n}"
   1.109 +proof (induction n)
   1.110 +case (Suc n)
   1.111 +  have "int (Suc n) = int n + 1" by simp
   1.112 +  hence "insert (int (Suc n)) {0<..int n} = {0<..int (Suc n)}" by auto
   1.113 +  thus ?case using prod.insert[of "{0<..int n}" "int (Suc n)" "\<lambda>x. x"] Suc fact_Suc by auto
   1.114 +qed simp
   1.115 +
   1.116 +private lemma l8: "fact (p - 1) = \<Prod> S1" using l7[of "p - 1"] S1_def p_minus_1_int by presburger
   1.117 +
   1.118 +private lemma l9: "[prod Prod S2 = -1] (mod p)"
   1.119 +  using l6 l8 wilson_theorem[of p] p_prime by presburger
   1.120 +
   1.121 +private lemma l10: assumes "card S = n" "\<And>x. x \<in> S \<Longrightarrow> [g x = a] (mod p)"
   1.122 +  shows "[prod g S = a ^ n] (mod p)" using assms
   1.123 +proof (induction n arbitrary: S)
   1.124 +case 0
   1.125 +  thus ?case using card_0_eq[of S] prod.empty prod.infinite by fastforce
   1.126 +next
   1.127 +case (Suc n)
   1.128 +  then obtain x where x: "x \<in> S" by force
   1.129 +  define S' where "S' = S - {x}"
   1.130 +  hence "[prod g S' = a ^ n] (mod int p)"
   1.131 +    using x Suc(1)[of S'] Suc(2) Suc(3) by (simp add: card_ge_0_finite)
   1.132 +  moreover have "prod g S = g x * prod g S'"
   1.133 +    using x S'_def Suc(2) prod.remove[of S x g] by fastforce
   1.134 +  ultimately show ?case using x Suc(3) cong_mult_int by simp
   1.135 +qed
   1.136 +
   1.137 +private lemma l11: assumes "~ QuadRes p a"
   1.138 +  shows "card S2 = (p - 1) div 2"
   1.139 +proof -
   1.140 +  have "sum card S2 = 2 * card S2"
   1.141 +    using sum.cong[of S2 S2 card "\<lambda>x. 2"] l1 f_def S2_def assms by fastforce
   1.142 +  moreover have "p - 1 = sum card S2"
   1.143 +    using l4 card_UN_disjoint[of S2 "\<lambda>x. x"] l3 l5 S1_def S2_def by auto
   1.144 +  ultimately show ?thesis by linarith
   1.145 +qed
   1.146 +
   1.147 +private lemma l12: assumes "~ QuadRes p a"
   1.148 +  shows "[prod Prod S2 = a ^ ((p - 1) div 2)] (mod p)"
   1.149 +  using assms l2 l10 l11 unfolding S2_def by blast
   1.150 +
   1.151 +private lemma E_2: assumes "~ QuadRes p a"
   1.152 +  shows "[a ^ ((p - 1) div 2) = -1] (mod p)" using l9 l12 cong_trans_int cong_sym_int assms by blast
   1.153 +
   1.154 +lemma euler_criterion_aux: "[(Legendre a p) = a ^ ((p - 1) div 2)] (mod p)"
   1.155 +  using E_1 E_2 Legendre_def cong_sym_int p_a_relprime by presburger
   1.156 +
   1.157 +end
   1.158 +
   1.159 +theorem euler_criterion: assumes "prime p" "2 < p"
   1.160 +  shows "[(Legendre a p) = a ^ ((p - 1) div 2)] (mod p)"
   1.161 +proof (cases "[a = 0] (mod p)")
   1.162 +case True
   1.163 +  hence "[a ^ ((p - 1) div 2) = 0 ^ ((p - 1) div 2)] (mod p)" using cong_exp_int by blast
   1.164 +  moreover have "(0::int) ^ ((p - 1) div 2) = 0" using zero_power[of "(p - 1) div 2"] assms(2) by simp
   1.165 +  ultimately have "[a ^ ((p - 1) div 2) = 0] (mod p)" using cong_trans_int cong_refl_int by presburger
   1.166 +  thus ?thesis unfolding Legendre_def using True cong_sym_int by presburger
   1.167 +next
   1.168 +case False
   1.169 +  thus ?thesis using euler_criterion_aux assms by presburger
   1.170 +qed
   1.171 +
   1.172 +hide_fact euler_criterion_aux
   1.173 +
   1.174 +end
     2.1 --- a/src/HOL/Number_Theory/Gauss.thy	Tue Oct 18 07:04:08 2016 +0200
     2.2 +++ b/src/HOL/Number_Theory/Gauss.thy	Mon Oct 17 15:20:06 2016 +0200
     2.3 @@ -6,7 +6,7 @@
     2.4  section \<open>Gauss' Lemma\<close>
     2.5  
     2.6  theory Gauss
     2.7 -imports Residues
     2.8 +imports Euler_Criterion
     2.9  begin
    2.10  
    2.11  lemma cong_prime_prod_zero_nat: 
    2.12 @@ -373,25 +373,24 @@
    2.13      by (simp add: A_card_eq cong_sym_int)
    2.14  qed
    2.15  
    2.16 -(*NOT WORKING. Old_Number_Theory/Euler.thy needs to be translated, but it's
    2.17 -quite a mess and should better be completely redone.
    2.18 -
    2.19  theorem gauss_lemma: "(Legendre a p) = (-1) ^ (card E)"
    2.20  proof -
    2.21 -  from Euler_Criterion p_prime p_ge_2 have
    2.22 +  from euler_criterion p_prime p_ge_2 have
    2.23        "[(Legendre a p) = a^(nat (((p) - 1) div 2))] (mod p)"
    2.24      by auto
    2.25 +  moreover have "int ((p - 1) div 2) =(int p - 1) div 2" using p_eq2 by linarith
    2.26 +    hence "[a ^ nat (int ((p - 1) div 2)) = a ^ nat ((int p - 1) div 2)] (mod int p)" by force
    2.27    moreover note pre_gauss_lemma
    2.28 -  ultimately have "[(Legendre a p) = (-1) ^ (card E)] (mod p)"
    2.29 -    by (rule cong_trans_int)
    2.30 +  ultimately have "[(Legendre a p) = (-1) ^ (card E)] (mod p)" using cong_trans_int by blast
    2.31    moreover from p_a_relprime have "(Legendre a p) = 1 | (Legendre a p) = (-1)"
    2.32      by (auto simp add: Legendre_def)
    2.33    moreover have "(-1::int) ^ (card E) = 1 | (-1::int) ^ (card E) = -1"
    2.34 -    by (rule neg_one_power)
    2.35 +    using neg_one_even_power neg_one_odd_power by blast
    2.36 +  moreover have "[1 \<noteq> - 1] (mod int p)"
    2.37 +    using cong_altdef_int nonzero_mod_p[of 2] p_odd_int by fastforce
    2.38    ultimately show ?thesis
    2.39 -    by (auto simp add: p_ge_2 one_not_neg_one_mod_m zcong_sym)
    2.40 +    by (auto simp add: cong_sym_int)
    2.41  qed
    2.42 -*)
    2.43  
    2.44  end
    2.45  
     3.1 --- a/src/HOL/Number_Theory/Number_Theory.thy	Tue Oct 18 07:04:08 2016 +0200
     3.2 +++ b/src/HOL/Number_Theory/Number_Theory.thy	Mon Oct 17 15:20:06 2016 +0200
     3.3 @@ -2,7 +2,7 @@
     3.4  section \<open>Comprehensive number theory\<close>
     3.5  
     3.6  theory Number_Theory
     3.7 -imports Fib Residues Eratosthenes
     3.8 +imports Fib Residues Eratosthenes QuadraticReciprocity Pocklington
     3.9  begin
    3.10  
    3.11  end
     4.1 --- a/src/HOL/Number_Theory/Pocklington.thy	Tue Oct 18 07:04:08 2016 +0200
     4.2 +++ b/src/HOL/Number_Theory/Pocklington.thy	Mon Oct 17 15:20:06 2016 +0200
     4.3 @@ -10,7 +10,7 @@
     4.4  
     4.5  subsection\<open>Lemmas about previously defined terms\<close>
     4.6  
     4.7 -lemma prime: 
     4.8 +lemma prime_nat_iff'':
     4.9    "prime (p::nat) \<longleftrightarrow> p \<noteq> 0 \<and> p \<noteq> 1 \<and> (\<forall>m. 0 < m \<and> m < p \<longrightarrow> coprime p m)"
    4.10    unfolding prime_nat_iff
    4.11  proof safe
    4.12 @@ -78,7 +78,7 @@
    4.13    from pa have ap: "coprime a p"
    4.14      by (metis gcd.commute) 
    4.15    have px:"coprime x p"
    4.16 -    by (metis gcd.commute p prime x0 xp)
    4.17 +    by (metis gcd.commute p prime_nat_iff'' x0 xp)
    4.18    obtain y where y: "y < p" "[x * y = a] (mod p)" "\<forall>z. z < p \<and> [x * z = a] (mod p) \<longrightarrow> z = y"
    4.19      by (metis cong_solve_unique neq0_conv p prime_gt_0_nat px)
    4.20    {assume y0: "y = 0"
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/HOL/Number_Theory/QuadraticReciprocity.thy	Mon Oct 17 15:20:06 2016 +0200
     5.3 @@ -0,0 +1,387 @@
     5.4 +(* Author: Jaime Mendizabal Roche *)
     5.5 +
     5.6 +theory QuadraticReciprocity
     5.7 +imports Gauss
     5.8 +begin
     5.9 +
    5.10 +text {* The proof is based on Gauss's fifth proof, which can be found at http://www.lehigh.edu/~shw2/q-recip/gauss5.pdf *}
    5.11 +
    5.12 +locale QR =
    5.13 +  fixes p :: "nat"
    5.14 +  fixes q :: "nat"
    5.15 +
    5.16 +  assumes p_prime: "prime p"
    5.17 +  assumes p_ge_2: "2 < p"
    5.18 +  assumes q_prime: "prime q"
    5.19 +  assumes q_ge_2: "2 < q"
    5.20 +  assumes pq_neq: "p \<noteq> q"
    5.21 +begin
    5.22 +
    5.23 +lemma odd_p: "odd p" using p_ge_2 p_prime prime_odd_nat by blast
    5.24 +
    5.25 +lemma p_ge_0: "0 < int p"
    5.26 +  using p_prime not_prime_0[where 'a = nat] by fastforce+
    5.27 +
    5.28 +lemma p_eq2: "int p = (2 * ((int p - 1) div 2)) + 1" using odd_p by simp
    5.29 +
    5.30 +lemma odd_q: "odd q" using q_ge_2 q_prime prime_odd_nat by blast
    5.31 +
    5.32 +lemma q_ge_0: "0 < int q" using q_prime not_prime_0[where 'a = nat] by fastforce+
    5.33 +
    5.34 +lemma q_eq2: "int q = (2 * ((int q - 1) div 2)) + 1" using odd_q by simp
    5.35 +
    5.36 +lemma pq_eq2: "int p * int q = (2 * ((int p * int q - 1) div 2)) + 1" using odd_p odd_q by simp
    5.37 +
    5.38 +lemma pq_coprime: "coprime p q"
    5.39 +  using pq_neq p_prime primes_coprime_nat q_prime by blast
    5.40 +
    5.41 +lemma pq_coprime_int: "coprime (int p) (int q)"
    5.42 +  using pq_coprime transfer_int_nat_gcd(1) by presburger
    5.43 +
    5.44 +lemma qp_ineq: "(int p * k \<le> (int p * int q - 1) div 2) = (k \<le> (int q - 1) div 2)"
    5.45 +proof -
    5.46 +  have "(2 * int p * k \<le> int p * int q - 1) = (2 * k \<le> int q - 1)" using p_ge_0 by auto
    5.47 +  thus ?thesis by auto
    5.48 +qed
    5.49 +
    5.50 +lemma QRqp: "QR q p" using QR_def QR_axioms by simp
    5.51 +
    5.52 +lemma pq_commute: "int p * int q = int q * int p" by simp
    5.53 +
    5.54 +lemma pq_ge_0: "int p * int q > 0" using p_ge_0 q_ge_0 mult_pos_pos by blast
    5.55 +
    5.56 +definition "r = ((p - 1) div 2)*((q - 1) div 2)"
    5.57 +definition "m = card (GAUSS.E p q)"
    5.58 +definition "n = card (GAUSS.E q p)"
    5.59 +
    5.60 +abbreviation "Res (k::int) \<equiv> {0 .. k - 1}"
    5.61 +abbreviation "Res_ge_0 (k::int) \<equiv> {0 <.. k - 1}"
    5.62 +abbreviation "Res_0 (k::int) \<equiv> {0::int}"
    5.63 +abbreviation "Res_l (k::int) \<equiv> {0 <.. (k - 1) div 2}"
    5.64 +abbreviation "Res_h (k::int) \<equiv> {(k - 1) div 2 <.. k - 1}"
    5.65 +
    5.66 +abbreviation "Sets_pq r0 r1 r2 \<equiv>
    5.67 +  {(x::int). x \<in> r0 (int p * int q) \<and> x mod p \<in> r1 (int p) \<and> x mod q \<in> r2 (int q)}"
    5.68 +
    5.69 +definition "A = Sets_pq Res_l Res_l Res_h"
    5.70 +definition "B = Sets_pq Res_l Res_h Res_l"
    5.71 +definition "C = Sets_pq Res_h Res_h Res_l"
    5.72 +definition "D = Sets_pq Res_l Res_h Res_h"
    5.73 +definition "E = Sets_pq Res_l Res_0 Res_h"
    5.74 +definition "F = Sets_pq Res_l Res_h Res_0"
    5.75 +
    5.76 +definition "a = card A"
    5.77 +definition "b = card B"
    5.78 +definition "c = card C"
    5.79 +definition "d = card D"
    5.80 +definition "e = card E"
    5.81 +definition "f = card F"
    5.82 +
    5.83 +lemma Gpq: "GAUSS p q" unfolding GAUSS_def
    5.84 +  using p_prime pq_neq p_ge_2 q_prime
    5.85 +  by (auto simp: cong_altdef_int zdvd_int [symmetric] dest: primes_dvd_imp_eq) 
    5.86 +
    5.87 +lemma Gqp: "GAUSS q p" using QRqp QR.Gpq by simp
    5.88 +
    5.89 +lemma QR_lemma_01: "(\<lambda>x. x mod q) ` E = GAUSS.E q p"
    5.90 +proof
    5.91 +    {
    5.92 +      fix x
    5.93 +      assume a1: "x \<in> E"
    5.94 +      then obtain k where k: "x = int p * k" unfolding E_def by blast
    5.95 +      have "x \<in> Res_l (int p * int q)" using a1 E_def by blast
    5.96 +      hence "k \<in> GAUSS.A q" using Gqp GAUSS.A_def k qp_ineq by (simp add: zero_less_mult_iff)
    5.97 +      hence "x mod q \<in> GAUSS.E q p"
    5.98 +        using GAUSS.C_def[of q p] Gqp k GAUSS.B_def[of q p] a1 GAUSS.E_def[of q p]
    5.99 +        unfolding E_def by force
   5.100 +      hence "x \<in> E \<longrightarrow> x mod int q \<in> GAUSS.E q p" by auto
   5.101 +    }
   5.102 +    thus "(\<lambda>x. x mod int q) ` E \<subseteq> GAUSS.E q p" by auto
   5.103 +next
   5.104 +  show "GAUSS.E q p \<subseteq> (\<lambda>x. x mod q) ` E"
   5.105 +  proof
   5.106 +    fix x
   5.107 +    assume a1: "x \<in> GAUSS.E q p"
   5.108 +    then obtain ka where ka: "ka \<in> GAUSS.A q" "x = (ka * p) mod q"
   5.109 +      using Gqp GAUSS.B_def GAUSS.C_def GAUSS.E_def by auto
   5.110 +    hence "ka * p \<in> Res_l (int p * int q)"
   5.111 +      using GAUSS.A_def Gqp p_ge_0 qp_ineq by (simp add: Groups.mult_ac(2))
   5.112 +    thus "x \<in> (\<lambda>x. x mod q) ` E" unfolding E_def using ka a1 Gqp GAUSS.E_def q_ge_0 by force
   5.113 +  qed
   5.114 +qed
   5.115 +
   5.116 +lemma QR_lemma_02: "e= n"
   5.117 +proof -
   5.118 +  {
   5.119 +    fix x y
   5.120 +    assume a: "x \<in> E" "y \<in> E" "x mod q = y mod q"
   5.121 +    obtain p_inv where p_inv: "[int p * p_inv = 1] (mod int q)"
   5.122 +      using pq_coprime_int cong_solve_coprime_int by blast
   5.123 +    obtain kx ky where k: "x = int p * kx" "y = int p * ky" using a E_def dvd_def[of p x] by blast
   5.124 +    hence "0 < x" "int p * kx \<le> (int p * int q - 1) div 2"
   5.125 +        "0 < y" "int p * ky \<le> (int p * int q - 1) div 2"
   5.126 +      using E_def a greaterThanAtMost_iff mem_Collect_eq by blast+
   5.127 +    hence "0 \<le> kx" "kx < q" "0 \<le> ky" "ky < q" using qp_ineq k by (simp add: zero_less_mult_iff)+
   5.128 +    moreover have "(p_inv * (p * kx)) mod q = (p_inv * (p * ky)) mod q"
   5.129 +      using a(3) mod_mult_cong k by blast
   5.130 +    hence "(p * p_inv * kx) mod q = (p * p_inv * ky) mod q" by (simp add:algebra_simps)
   5.131 +    hence "kx mod q = ky mod q"
   5.132 +      using p_inv mod_mult_cong[of "p * p_inv" "q" "1"] cong_int_def by auto
   5.133 +    hence "[kx = ky] (mod q)" using cong_int_def by blast
   5.134 +    ultimately have "x = y" using cong_less_imp_eq_int k by blast
   5.135 +  }
   5.136 +  hence "inj_on (\<lambda>x. x mod q) E" unfolding inj_on_def by auto
   5.137 +  thus ?thesis using QR_lemma_01 card_image e_def n_def by fastforce
   5.138 +qed
   5.139 +
   5.140 +lemma QR_lemma_03: "f = m"
   5.141 +proof -
   5.142 +  have "F = QR.E q p" unfolding F_def pq_commute using QRqp QR.E_def[of q p] by fastforce
   5.143 +  hence "f = QR.e q p" unfolding f_def using QRqp QR.e_def[of q p] by presburger
   5.144 +  thus ?thesis using QRqp QR.QR_lemma_02 m_def QRqp QR.n_def by presburger
   5.145 +qed
   5.146 +
   5.147 +definition f_1 :: "int \<Rightarrow> int \<times> int" where
   5.148 +  "f_1 x = ((x mod p), (x mod q))"
   5.149 +
   5.150 +definition P_1 :: "int \<times> int \<Rightarrow> int \<Rightarrow> bool" where
   5.151 +  "P_1 res x \<longleftrightarrow> x mod p = fst res & x mod q = snd res & x \<in> Res (int p * int q)"
   5.152 +
   5.153 +definition g_1 :: "int \<times> int \<Rightarrow> int" where
   5.154 +  "g_1 res = (THE x. P_1 res x)"
   5.155 +
   5.156 +lemma P_1_lemma: assumes "0 \<le> fst res" "fst res < p" "0 \<le> snd res" "snd res < q"
   5.157 +  shows "\<exists>! x. P_1 res x"
   5.158 +proof -
   5.159 +  obtain y k1 k2 where yk: "y = nat (fst res) + k1 * p" "y = nat (snd res) + k2 * q"
   5.160 +    using chinese_remainder[of p q] pq_coprime p_ge_0 q_ge_0 by fastforce
   5.161 +  have h1: "[y = fst res] (mod p)" "[y = snd res] (mod q)"
   5.162 +    using yk(1) assms(1) cong_iff_lin_int[of "fst res"] cong_sym_int apply simp
   5.163 +    using yk(2) assms(3) cong_iff_lin_int[of "snd res"] cong_sym_int by simp
   5.164 +  have "(y mod (int p * int q)) mod int p = fst res" "(y mod (int p * int q)) mod int q = snd res"
   5.165 +    using h1(1) mod_mod_cancel[of "int p"] assms(1) assms(2) cong_int_def apply simp
   5.166 +    using h1(2) mod_mod_cancel[of "int q"] assms(3) assms(4) cong_int_def by simp
   5.167 +  then obtain x where "P_1 res x" unfolding P_1_def
   5.168 +    using Divides.pos_mod_bound Divides.pos_mod_sign pq_ge_0 by fastforce
   5.169 +  moreover {
   5.170 +    fix a b
   5.171 +    assume a: "P_1 res a" "P_1 res b"
   5.172 +    hence "int p * int q dvd a - b"
   5.173 +      using divides_mult[of "int p" "a - b" "int q"] pq_coprime_int zmod_eq_dvd_iff[of a _ b]
   5.174 +      unfolding P_1_def by force
   5.175 +    hence "a = b" using dvd_imp_le_int[of "a - b"] a unfolding P_1_def by fastforce
   5.176 +  }
   5.177 +  ultimately show ?thesis by auto
   5.178 +qed
   5.179 +
   5.180 +lemma g_1_lemma: assumes "0 \<le> fst res" "fst res < p" "0 \<le> snd res" "snd res < q"
   5.181 +  shows "P_1 res (g_1 res)" using assms P_1_lemma theI'[of "P_1 res"] g_1_def by presburger
   5.182 +
   5.183 +definition "BuC = Sets_pq Res_ge_0 Res_h Res_l"
   5.184 +
   5.185 +lemma QR_lemma_04: "card BuC = card ((Res_h p) \<times> (Res_l q))"
   5.186 +  using card_bij_eq[of f_1 "BuC" "(Res_h p) \<times> (Res_l q)" g_1]
   5.187 +proof
   5.188 +  {
   5.189 +    fix x y
   5.190 +    assume a: "x \<in> BuC" "y \<in> BuC" "f_1 x = f_1 y"
   5.191 +    hence "int p * int q dvd x - y"
   5.192 +      using f_1_def pq_coprime_int divides_mult[of "int p" "x - y" "int q"] 
   5.193 +            zmod_eq_dvd_iff[of x _ y] by auto
   5.194 +    hence "x = y"
   5.195 +      using dvd_imp_le_int[of "x - y" "int p * int q"] a unfolding BuC_def by force
   5.196 +  }
   5.197 +  thus "inj_on f_1 BuC" unfolding inj_on_def by auto
   5.198 +next
   5.199 +  {
   5.200 +    fix x y
   5.201 +    assume a: "x \<in> (Res_h p) \<times> (Res_l q)" "y \<in> (Res_h p) \<times> (Res_l q)" "g_1 x = g_1 y"
   5.202 +    hence "0 \<le> fst x" "fst x < p" "0 \<le> snd x" "snd x < q"
   5.203 +        "0 \<le> fst y" "fst y < p" "0 \<le> snd y" "snd y < q"
   5.204 +      using mem_Sigma_iff prod.collapse by fastforce+
   5.205 +    hence "x = y" using g_1_lemma[of x] g_1_lemma[of y] a P_1_def by fastforce
   5.206 +  }
   5.207 +  thus "inj_on g_1 ((Res_h p) \<times> (Res_l q))" unfolding inj_on_def by auto
   5.208 +next
   5.209 +  show "g_1 ` ((Res_h p) \<times> (Res_l q)) \<subseteq> BuC"
   5.210 +  proof
   5.211 +    fix y
   5.212 +    assume "y \<in> g_1 ` ((Res_h p) \<times> (Res_l q))"
   5.213 +    then obtain x where x: "y = g_1 x" "x \<in> ((Res_h p) \<times> (Res_l q))" by blast
   5.214 +    hence "P_1 x y" using g_1_lemma by fastforce
   5.215 +    thus "y \<in> BuC" unfolding P_1_def BuC_def mem_Collect_eq using x SigmaE prod.sel by fastforce
   5.216 +  qed
   5.217 +qed (auto simp: BuC_def finite_subset f_1_def)
   5.218 +
   5.219 +lemma QR_lemma_05: "card ((Res_h p) \<times> (Res_l q)) = r"
   5.220 +proof -
   5.221 +  have "card (Res_l q) = (q - 1) div 2" "card (Res_h p) = (p - 1) div 2" using p_eq2 by force+
   5.222 +  thus ?thesis unfolding r_def using card_cartesian_product[of "Res_h p" "Res_l q"] by presburger
   5.223 +qed
   5.224 +
   5.225 +lemma QR_lemma_06: "b + c = r"
   5.226 +proof -
   5.227 +  have "B \<inter> C = {}" "finite B" "finite C" "B \<union> C = BuC" unfolding B_def C_def BuC_def by fastforce+
   5.228 +  thus ?thesis
   5.229 +    unfolding b_def c_def using card_empty card_Un_Int QR_lemma_04 QR_lemma_05 by fastforce
   5.230 +qed
   5.231 +
   5.232 +definition f_2:: "int \<Rightarrow> int" where
   5.233 +  "f_2 x = (int p * int q) - x"
   5.234 +
   5.235 +lemma f_2_lemma_1: "\<And>x. f_2 (f_2 x) = x" unfolding f_2_def by simp
   5.236 +
   5.237 +lemma f_2_lemma_2: "[f_2 x = int p - x] (mod p)" unfolding f_2_def using cong_altdef_int by simp
   5.238 +
   5.239 +lemma f_2_lemma_3: "f_2 x \<in> S \<Longrightarrow> x \<in> f_2 ` S"
   5.240 +  using f_2_lemma_1[of x] image_eqI[of x f_2 "f_2 x" S] by presburger
   5.241 +
   5.242 +lemma QR_lemma_07: "f_2 ` Res_l (int p * int q) = Res_h (int p * int q)"
   5.243 +    "f_2 ` Res_h (int p * int q) = Res_l (int p * int q)"
   5.244 +proof -
   5.245 +  have h1: "f_2 ` Res_l (int p * int q) \<subseteq> Res_h (int p * int q)" using f_2_def by force
   5.246 +  have h2: "f_2 ` Res_h (int p * int q) \<subseteq> Res_l (int p * int q)" using f_2_def pq_eq2 by fastforce
   5.247 +  have h3: "Res_h (int p * int q) \<subseteq> f_2 ` Res_l (int p * int q)" using h2 f_2_lemma_3 by blast
   5.248 +  have h4: "Res_l (int p * int q) \<subseteq> f_2 ` Res_h (int p * int q)" using h1 f_2_lemma_3 by blast
   5.249 +  show "f_2 ` Res_l (int p * int q) = Res_h (int p * int q)" using h1 h3 by blast
   5.250 +  show "f_2 ` Res_h (int p * int q) = Res_l (int p * int q)" using h2 h4 by blast
   5.251 +qed
   5.252 +
   5.253 +lemma QR_lemma_08: "(f_2 x mod p \<in> Res_l p) = (x mod p \<in> Res_h p)"
   5.254 +    "(f_2 x mod p \<in> Res_h p) = (x mod p \<in> Res_l p)"
   5.255 +  using f_2_lemma_2[of x] cong_int_def[of "f_2 x" "p - x" p] minus_mod_self2[of x p]
   5.256 +  zmod_zminus1_eq_if[of x p] p_eq2 by auto
   5.257 +
   5.258 +lemma QR_lemma_09: "(f_2 x mod q \<in> Res_l q) = (x mod q \<in> Res_h q)"
   5.259 +    "(f_2 x mod q \<in> Res_h q) = (x mod q \<in> Res_l q)"
   5.260 +  using QRqp QR.QR_lemma_08 f_2_def QR.f_2_def pq_commute by auto+
   5.261 +
   5.262 +lemma QR_lemma_10: "a = c" unfolding a_def c_def apply (rule card_bij_eq[of f_2 A C f_2])
   5.263 +  unfolding A_def C_def
   5.264 +  using QR_lemma_07 QR_lemma_08 QR_lemma_09 apply ((simp add: inj_on_def f_2_def),blast)+
   5.265 +  by fastforce+
   5.266 +
   5.267 +definition "BuD = Sets_pq Res_l Res_h Res_ge_0"
   5.268 +definition "BuDuF = Sets_pq Res_l Res_h Res"
   5.269 +
   5.270 +definition f_3 :: "int \<Rightarrow> int \<times> int" where
   5.271 +  "f_3 x = (x mod p, x div p + 1)"
   5.272 +
   5.273 +definition g_3 :: "int \<times> int \<Rightarrow> int" where
   5.274 +  "g_3 x = fst x + (snd x - 1) * p"
   5.275 +
   5.276 +lemma QR_lemma_11: "card BuDuF = card ((Res_h p) \<times> (Res_l q))"
   5.277 +  using card_bij_eq[of f_3 BuDuF "(Res_h p) \<times> (Res_l q)" g_3]
   5.278 +proof
   5.279 +  show "f_3 ` BuDuF \<subseteq> (Res_h p) \<times> (Res_l q)"
   5.280 +  proof
   5.281 +    fix y
   5.282 +    assume "y \<in> f_3 ` BuDuF"
   5.283 +    then obtain x where x: "y = f_3 x" "x \<in> BuDuF" by blast
   5.284 +    hence "x \<le> int p * (int q - 1) div 2 + (int p - 1) div 2"
   5.285 +      unfolding BuDuF_def using p_eq2 int_distrib(4) by auto
   5.286 +    moreover have "(int p - 1) div 2 \<le> - 1 + x mod p" using x BuDuF_def by auto
   5.287 +    moreover have "int p * (int q - 1) div 2 = int p * ((int q - 1) div 2)"
   5.288 +      using zdiv_zmult1_eq odd_q by auto
   5.289 +    hence "p * (int q - 1) div 2 = p * ((int q + 1) div 2 - 1)" by fastforce
   5.290 +    ultimately have "x \<le> p * ((int q + 1) div 2 - 1) - 1 + x mod p" by linarith
   5.291 +    hence "x div p < (int q + 1) div 2 - 1"
   5.292 +      using mult.commute[of "int p" "x div p"] p_ge_0 div_mult_mod_eq[of x p]
   5.293 +        mult_less_cancel_left_pos[of p "x div p" "(int q + 1) div 2 - 1"] by linarith
   5.294 +    moreover have "0 < x div p + 1"
   5.295 +      using pos_imp_zdiv_neg_iff[of p x] p_ge_0 x mem_Collect_eq BuDuF_def by auto
   5.296 +    ultimately show "y \<in> (Res_h p) \<times> (Res_l q)" using x BuDuF_def f_3_def by auto
   5.297 +  qed
   5.298 +next
   5.299 +  have h1: "\<And>x. x \<in> ((Res_h p) \<times> (Res_l q)) \<Longrightarrow> f_3 (g_3 x) = x"
   5.300 +  proof -
   5.301 +    fix x
   5.302 +    assume a: "x \<in> ((Res_h p) \<times> (Res_l q))"
   5.303 +    moreover have h: "(fst x + (snd x - 1) * int p) mod int p = fst x" using a by force
   5.304 +    ultimately have "(fst x + (snd x - 1) * int p) div int p + 1 = snd x"
   5.305 +      by (auto simp: semiring_numeral_div_class.div_less)
   5.306 +    with h show "f_3 (g_3 x) = x" unfolding f_3_def g_3_def by simp
   5.307 +  qed
   5.308 +  show "inj_on g_3 ((Res_h p) \<times> (Res_l q))" apply (rule inj_onI[of "(Res_h p) \<times> (Res_l q)" g_3])
   5.309 +  proof -
   5.310 +    fix x y
   5.311 +    assume "x \<in> ((Res_h p) \<times> (Res_l q))" "y \<in> ((Res_h p) \<times> (Res_l q))" "g_3 x = g_3 y"
   5.312 +    thus "x = y" using h1[of x] h1[of y] by presburger
   5.313 +  qed
   5.314 +next
   5.315 +  show "g_3 ` ((Res_h p) \<times> (Res_l q)) \<subseteq> BuDuF"
   5.316 +  proof
   5.317 +    fix y
   5.318 +    assume "y \<in> g_3 ` ((Res_h p) \<times> (Res_l q))"
   5.319 +    then obtain x where x: "y = g_3 x" "x \<in> (Res_h p) \<times> (Res_l q)" by blast
   5.320 +    hence "snd x \<le> (int q - 1) div 2" by force
   5.321 +    moreover have "int p * ((int q - 1) div 2) = (int p * int q - int p) div 2"
   5.322 +      using int_distrib(4) zdiv_zmult1_eq[of "int p" "int q - 1" 2] odd_q by fastforce
   5.323 +    ultimately have "(snd x) * int p \<le> (int q * int p - int p) div 2"
   5.324 +      using mult_right_mono[of "snd x" "(int q - 1) div 2" p] mult.commute[of "(int q - 1) div 2" p]
   5.325 +        pq_commute by presburger
   5.326 +    hence "(snd x - 1) * int p \<le> (int q * int p - 1) div 2 - int p"
   5.327 +      using p_ge_0 int_distrib(3) by auto
   5.328 +    moreover have "fst x \<le> int p - 1" using x by force
   5.329 +    ultimately have "fst x + (snd x - 1) * int p \<le> (int p * int q - 1) div 2"
   5.330 +      using pq_commute by linarith
   5.331 +    moreover have "0 < fst x" "0 \<le> (snd x - 1) * p" using x(2) by fastforce+
   5.332 +    ultimately show "y \<in> BuDuF" unfolding BuDuF_def using q_ge_0 x g_3_def x(1) by auto
   5.333 +  qed
   5.334 +next
   5.335 +  show "finite BuDuF" unfolding BuDuF_def by fastforce
   5.336 +qed (simp add: inj_on_inverseI[of BuDuF g_3] f_3_def g_3_def QR_lemma_05)+
   5.337 +
   5.338 +lemma QR_lemma_12: "b + d + m = r"
   5.339 +proof -
   5.340 +  have "B \<inter> D = {}" "finite B" "finite D" "B \<union> D = BuD" unfolding B_def D_def BuD_def by fastforce+
   5.341 +  hence "b + d = card BuD" unfolding b_def d_def using card_Un_Int by fastforce
   5.342 +  moreover have "BuD \<inter> F = {}" "finite BuD" "finite F" unfolding BuD_def F_def by fastforce+
   5.343 +  moreover have "BuD \<union> F = BuDuF" unfolding BuD_def F_def BuDuF_def
   5.344 +    using q_ge_0 ivl_disj_un_singleton(5)[of 0 "int q - 1"] by auto
   5.345 +  ultimately show ?thesis using QR_lemma_03 QR_lemma_05 QR_lemma_11 card_Un_disjoint[of BuD F]
   5.346 +    unfolding b_def d_def f_def by presburger
   5.347 +qed
   5.348 +
   5.349 +lemma QR_lemma_13: "a + d + n = r"
   5.350 +proof -
   5.351 +  have "A = QR.B q p" unfolding A_def pq_commute using QRqp QR.B_def[of q p] by blast
   5.352 +  hence "a = QR.b q p" using a_def QRqp QR.b_def[of q p] by presburger
   5.353 +  moreover have "D = QR.D q p" unfolding D_def pq_commute using QRqp QR.D_def[of q p] by blast
   5.354 +    hence "d = QR.d q p" using d_def  QRqp QR.d_def[of q p] by presburger
   5.355 +  moreover have "n = QR.m q p" using n_def QRqp QR.m_def[of q p] by presburger
   5.356 +  moreover have "r = QR.r q p" unfolding r_def using QRqp QR.r_def[of q p] by auto
   5.357 +  ultimately show ?thesis using QRqp QR.QR_lemma_12 by presburger
   5.358 +qed
   5.359 +
   5.360 +lemma QR_lemma_14: "(-1::int) ^ (m + n) = (-1) ^ r"
   5.361 +proof -
   5.362 +  have "m + n + 2 * d = r" using QR_lemma_06 QR_lemma_10 QR_lemma_12 QR_lemma_13 by auto
   5.363 +  thus ?thesis using power_add[of "-1::int" "m + n" "2 * d"] by fastforce
   5.364 +qed
   5.365 +
   5.366 +lemma Quadratic_Reciprocity:
   5.367 +    "(Legendre p q) * (Legendre q p) = (-1::int) ^ ((p - 1) div 2 * ((q - 1) div 2))"
   5.368 +  using Gpq Gqp GAUSS.gauss_lemma power_add[of "-1::int" m n] QR_lemma_14
   5.369 +  unfolding r_def m_def n_def by auto
   5.370 +
   5.371 +end
   5.372 +
   5.373 +theorem Quadratic_Reciprocity: assumes "prime p" "2 < p" "prime q" "2 < q" "p \<noteq> q"
   5.374 +  shows "(Legendre p q) * (Legendre q p) = (-1::int) ^ ((p - 1) div 2 * ((q - 1) div 2))"
   5.375 +  using QR.Quadratic_Reciprocity QR_def assms by blast
   5.376 +
   5.377 +theorem Quadratic_Reciprocity_int: assumes "prime (nat p)" "2 < p" "prime (nat q)" "2 < q" "p \<noteq> q"
   5.378 +  shows "(Legendre p q) * (Legendre q p) = (-1::int) ^ (nat ((p - 1) div 2 * ((q - 1) div 2)))"
   5.379 +proof -
   5.380 +  have "0 \<le> (p - 1) div 2" using assms by simp
   5.381 +  moreover have "(nat p - 1) div 2 = nat ((p - 1) div 2)" "(nat q - 1) div 2 = nat ((q - 1) div 2)"
   5.382 +    by fastforce+
   5.383 +  ultimately have "(nat p - 1) div 2 * ((nat q - 1) div 2) = nat ((p - 1) div 2 * ((q - 1) div 2))"
   5.384 +    using nat_mult_distrib by presburger
   5.385 +  moreover have "2 < nat p" "2 < nat q" "nat p \<noteq> nat q" "int (nat p) = p" "int (nat q) = q"
   5.386 +    using assms by linarith+
   5.387 +  ultimately show ?thesis using Quadratic_Reciprocity[of "nat p" "nat q"] assms by presburger
   5.388 +qed
   5.389 +
   5.390 +end
   5.391 \ No newline at end of file
     6.1 --- a/src/HOL/Number_Theory/Residues.thy	Tue Oct 18 07:04:08 2016 +0200
     6.2 +++ b/src/HOL/Number_Theory/Residues.thy	Mon Oct 17 15:20:06 2016 +0200
     6.3 @@ -11,6 +11,14 @@
     6.4  imports Cong MiscAlgebra
     6.5  begin
     6.6  
     6.7 +definition QuadRes :: "int \<Rightarrow> int \<Rightarrow> bool" where
     6.8 +  "QuadRes p a = (\<exists>y. ([y^2 = a] (mod p)))"
     6.9 +
    6.10 +definition Legendre :: "int \<Rightarrow> int \<Rightarrow> int" where
    6.11 +  "Legendre a p = (if ([a = 0] (mod p)) then 0
    6.12 +    else if QuadRes p a then 1
    6.13 +    else -1)"
    6.14 +
    6.15  subsection \<open>A locale for residue rings\<close>
    6.16  
    6.17  definition residue_ring :: "int \<Rightarrow> int ring"
     7.1 --- a/src/HOL/Old_Number_Theory/BijectionRel.thy	Tue Oct 18 07:04:08 2016 +0200
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,232 +0,0 @@
     7.4 -(*  Title:      HOL/Old_Number_Theory/BijectionRel.thy
     7.5 -    Author:     Thomas M. Rasmussen
     7.6 -    Copyright   2000  University of Cambridge
     7.7 -*)
     7.8 -
     7.9 -section \<open>Bijections between sets\<close>
    7.10 -
    7.11 -theory BijectionRel
    7.12 -imports Main
    7.13 -begin
    7.14 -
    7.15 -text \<open>
    7.16 -  Inductive definitions of bijections between two different sets and
    7.17 -  between the same set.  Theorem for relating the two definitions.
    7.18 -
    7.19 -  \bigskip
    7.20 -\<close>
    7.21 -
    7.22 -inductive_set
    7.23 -  bijR :: "('a => 'b => bool) => ('a set * 'b set) set"
    7.24 -  for P :: "'a => 'b => bool"
    7.25 -where
    7.26 -  empty [simp]: "({}, {}) \<in> bijR P"
    7.27 -| insert: "P a b ==> a \<notin> A ==> b \<notin> B ==> (A, B) \<in> bijR P
    7.28 -    ==> (insert a A, insert b B) \<in> bijR P"
    7.29 -
    7.30 -text \<open>
    7.31 -  Add extra condition to @{term insert}: @{term "\<forall>b \<in> B. \<not> P a b"}
    7.32 -  (and similar for @{term A}).
    7.33 -\<close>
    7.34 -
    7.35 -definition
    7.36 -  bijP :: "('a => 'a => bool) => 'a set => bool" where
    7.37 -  "bijP P F = (\<forall>a b. a \<in> F \<and> P a b --> b \<in> F)"
    7.38 -
    7.39 -definition
    7.40 -  uniqP :: "('a => 'a => bool) => bool" where
    7.41 -  "uniqP P = (\<forall>a b c d. P a b \<and> P c d --> (a = c) = (b = d))"
    7.42 -
    7.43 -definition
    7.44 -  symP :: "('a => 'a => bool) => bool" where
    7.45 -  "symP P = (\<forall>a b. P a b = P b a)"
    7.46 -
    7.47 -inductive_set
    7.48 -  bijER :: "('a => 'a => bool) => 'a set set"
    7.49 -  for P :: "'a => 'a => bool"
    7.50 -where
    7.51 -  empty [simp]: "{} \<in> bijER P"
    7.52 -| insert1: "P a a ==> a \<notin> A ==> A \<in> bijER P ==> insert a A \<in> bijER P"
    7.53 -| insert2: "P a b ==> a \<noteq> b ==> a \<notin> A ==> b \<notin> A ==> A \<in> bijER P
    7.54 -    ==> insert a (insert b A) \<in> bijER P"
    7.55 -
    7.56 -
    7.57 -text \<open>\medskip @{term bijR}\<close>
    7.58 -
    7.59 -lemma fin_bijRl: "(A, B) \<in> bijR P ==> finite A"
    7.60 -  apply (erule bijR.induct)
    7.61 -  apply auto
    7.62 -  done
    7.63 -
    7.64 -lemma fin_bijRr: "(A, B) \<in> bijR P ==> finite B"
    7.65 -  apply (erule bijR.induct)
    7.66 -  apply auto
    7.67 -  done
    7.68 -
    7.69 -lemma aux_induct:
    7.70 -  assumes major: "finite F"
    7.71 -    and subs: "F \<subseteq> A"
    7.72 -    and cases: "P {}"
    7.73 -      "!!F a. F \<subseteq> A ==> a \<in> A ==> a \<notin> F ==> P F ==> P (insert a F)"
    7.74 -  shows "P F"
    7.75 -  using major subs
    7.76 -  apply (induct set: finite)
    7.77 -   apply (blast intro: cases)+
    7.78 -  done
    7.79 -
    7.80 -
    7.81 -lemma inj_func_bijR_aux1:
    7.82 -    "A \<subseteq> B ==> a \<notin> A ==> a \<in> B ==> inj_on f B ==> f a \<notin> f ` A"
    7.83 -  apply (unfold inj_on_def)
    7.84 -  apply auto
    7.85 -  done
    7.86 -
    7.87 -lemma inj_func_bijR_aux2:
    7.88 -  "\<forall>a. a \<in> A --> P a (f a) ==> inj_on f A ==> finite A ==> F <= A
    7.89 -    ==> (F, f ` F) \<in> bijR P"
    7.90 -  apply (rule_tac F = F and A = A in aux_induct)
    7.91 -     apply (rule finite_subset)
    7.92 -      apply auto
    7.93 -  apply (rule bijR.insert)
    7.94 -     apply (rule_tac [3] inj_func_bijR_aux1)
    7.95 -        apply auto
    7.96 -  done
    7.97 -
    7.98 -lemma inj_func_bijR:
    7.99 -  "\<forall>a. a \<in> A --> P a (f a) ==> inj_on f A ==> finite A
   7.100 -    ==> (A, f ` A) \<in> bijR P"
   7.101 -  apply (rule inj_func_bijR_aux2)
   7.102 -     apply auto
   7.103 -  done
   7.104 -
   7.105 -
   7.106 -text \<open>\medskip @{term bijER}\<close>
   7.107 -
   7.108 -lemma fin_bijER: "A \<in> bijER P ==> finite A"
   7.109 -  apply (erule bijER.induct)
   7.110 -    apply auto
   7.111 -  done
   7.112 -
   7.113 -lemma aux1:
   7.114 -  "a \<notin> A ==> a \<notin> B ==> F \<subseteq> insert a A ==> F \<subseteq> insert a B ==> a \<in> F
   7.115 -    ==> \<exists>C. F = insert a C \<and> a \<notin> C \<and> C <= A \<and> C <= B"
   7.116 -  apply (rule_tac x = "F - {a}" in exI)
   7.117 -  apply auto
   7.118 -  done
   7.119 -
   7.120 -lemma aux2: "a \<noteq> b ==> a \<notin> A ==> b \<notin> B ==> a \<in> F ==> b \<in> F
   7.121 -    ==> F \<subseteq> insert a A ==> F \<subseteq> insert b B
   7.122 -    ==> \<exists>C. F = insert a (insert b C) \<and> a \<notin> C \<and> b \<notin> C \<and> C \<subseteq> A \<and> C \<subseteq> B"
   7.123 -  apply (rule_tac x = "F - {a, b}" in exI)
   7.124 -  apply auto
   7.125 -  done
   7.126 -
   7.127 -lemma aux_uniq: "uniqP P ==> P a b ==> P c d ==> (a = c) = (b = d)"
   7.128 -  apply (unfold uniqP_def)
   7.129 -  apply auto
   7.130 -  done
   7.131 -
   7.132 -lemma aux_sym: "symP P ==> P a b = P b a"
   7.133 -  apply (unfold symP_def)
   7.134 -  apply auto
   7.135 -  done
   7.136 -
   7.137 -lemma aux_in1:
   7.138 -    "uniqP P ==> b \<notin> C ==> P b b ==> bijP P (insert b C) ==> bijP P C"
   7.139 -  apply (unfold bijP_def)
   7.140 -  apply auto
   7.141 -  apply (subgoal_tac "b \<noteq> a")
   7.142 -   prefer 2
   7.143 -   apply clarify
   7.144 -  apply (simp add: aux_uniq)
   7.145 -  apply auto
   7.146 -  done
   7.147 -
   7.148 -lemma aux_in2:
   7.149 -  "symP P ==> uniqP P ==> a \<notin> C ==> b \<notin> C ==> a \<noteq> b ==> P a b
   7.150 -    ==> bijP P (insert a (insert b C)) ==> bijP P C"
   7.151 -  apply (unfold bijP_def)
   7.152 -  apply auto
   7.153 -  apply (subgoal_tac "aa \<noteq> a")
   7.154 -   prefer 2
   7.155 -   apply clarify
   7.156 -  apply (subgoal_tac "aa \<noteq> b")
   7.157 -   prefer 2
   7.158 -   apply clarify
   7.159 -  apply (simp add: aux_uniq)
   7.160 -  apply (subgoal_tac "ba \<noteq> a")
   7.161 -   apply auto
   7.162 -  apply (subgoal_tac "P a aa")
   7.163 -   prefer 2
   7.164 -   apply (simp add: aux_sym)
   7.165 -  apply (subgoal_tac "b = aa")
   7.166 -   apply (rule_tac [2] iffD1)
   7.167 -    apply (rule_tac [2] a = a and c = a and P = P in aux_uniq)
   7.168 -      apply auto
   7.169 -  done
   7.170 -
   7.171 -lemma aux_foo: "\<forall>a b. Q a \<and> P a b --> R b ==> P a b ==> Q a ==> R b"
   7.172 -  apply auto
   7.173 -  done
   7.174 -
   7.175 -lemma aux_bij: "bijP P F ==> symP P ==> P a b ==> (a \<in> F) = (b \<in> F)"
   7.176 -  apply (unfold bijP_def)
   7.177 -  apply (rule iffI)
   7.178 -  apply (erule_tac [!] aux_foo)
   7.179 -      apply simp_all
   7.180 -  apply (rule iffD2)
   7.181 -   apply (rule_tac P = P in aux_sym)
   7.182 -   apply simp_all
   7.183 -  done
   7.184 -
   7.185 -
   7.186 -lemma aux_bijRER:
   7.187 -  "(A, B) \<in> bijR P ==> uniqP P ==> symP P
   7.188 -    ==> \<forall>F. bijP P F \<and> F \<subseteq> A \<and> F \<subseteq> B --> F \<in> bijER P"
   7.189 -  apply (erule bijR.induct)
   7.190 -   apply simp
   7.191 -  apply (case_tac "a = b")
   7.192 -   apply clarify
   7.193 -   apply (case_tac "b \<in> F")
   7.194 -    prefer 2
   7.195 -    apply (simp add: subset_insert)
   7.196 -   apply (cut_tac F = F and a = b and A = A and B = B in aux1)
   7.197 -        prefer 6
   7.198 -        apply clarify
   7.199 -        apply (rule bijER.insert1)
   7.200 -          apply simp_all
   7.201 -   apply (subgoal_tac "bijP P C")
   7.202 -    apply simp
   7.203 -   apply (rule aux_in1)
   7.204 -      apply simp_all
   7.205 -  apply clarify
   7.206 -  apply (case_tac "a \<in> F")
   7.207 -   apply (case_tac [!] "b \<in> F")
   7.208 -     apply (cut_tac F = F and a = a and b = b and A = A and B = B
   7.209 -       in aux2)
   7.210 -            apply (simp_all add: subset_insert)
   7.211 -    apply clarify
   7.212 -    apply (rule bijER.insert2)
   7.213 -        apply simp_all
   7.214 -    apply (subgoal_tac "bijP P C")
   7.215 -     apply simp
   7.216 -    apply (rule aux_in2)
   7.217 -          apply simp_all
   7.218 -   apply (subgoal_tac "b \<in> F")
   7.219 -    apply (rule_tac [2] iffD1)
   7.220 -     apply (rule_tac [2] a = a and F = F and P = P in aux_bij)
   7.221 -       apply (simp_all (no_asm_simp))
   7.222 -   apply (subgoal_tac [2] "a \<in> F")
   7.223 -    apply (rule_tac [3] iffD2)
   7.224 -     apply (rule_tac [3] b = b and F = F and P = P in aux_bij)
   7.225 -       apply auto
   7.226 -  done
   7.227 -
   7.228 -lemma bijR_bijER:
   7.229 -  "(A, A) \<in> bijR P ==>
   7.230 -    bijP P A ==> uniqP P ==> symP P ==> A \<in> bijER P"
   7.231 -  apply (cut_tac A = A and B = A and P = P in aux_bijRER)
   7.232 -     apply auto
   7.233 -  done
   7.234 -
   7.235 -end
     8.1 --- a/src/HOL/Old_Number_Theory/Chinese.thy	Tue Oct 18 07:04:08 2016 +0200
     8.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.3 @@ -1,252 +0,0 @@
     8.4 -(*  Title:      HOL/Old_Number_Theory/Chinese.thy
     8.5 -    Author:     Thomas M. Rasmussen
     8.6 -    Copyright   2000  University of Cambridge
     8.7 -*)
     8.8 -
     8.9 -section \<open>The Chinese Remainder Theorem\<close>
    8.10 -
    8.11 -theory Chinese 
    8.12 -imports IntPrimes
    8.13 -begin
    8.14 -
    8.15 -text \<open>
    8.16 -  The Chinese Remainder Theorem for an arbitrary finite number of
    8.17 -  equations.  (The one-equation case is included in theory \<open>IntPrimes\<close>.  Uses functions for indexing.\footnote{Maybe @{term
    8.18 -  funprod} and @{term funsum} should be based on general @{term fold}
    8.19 -  on indices?}
    8.20 -\<close>
    8.21 -
    8.22 -
    8.23 -subsection \<open>Definitions\<close>
    8.24 -
    8.25 -primrec funprod :: "(nat => int) => nat => nat => int"
    8.26 -where
    8.27 -  "funprod f i 0 = f i"
    8.28 -| "funprod f i (Suc n) = f (Suc (i + n)) * funprod f i n"
    8.29 -
    8.30 -primrec funsum :: "(nat => int) => nat => nat => int"
    8.31 -where
    8.32 -  "funsum f i 0 = f i"
    8.33 -| "funsum f i (Suc n) = f (Suc (i + n)) + funsum f i n"
    8.34 -
    8.35 -definition
    8.36 -  m_cond :: "nat => (nat => int) => bool" where
    8.37 -  "m_cond n mf =
    8.38 -    ((\<forall>i. i \<le> n --> 0 < mf i) \<and>
    8.39 -      (\<forall>i j. i \<le> n \<and> j \<le> n \<and> i \<noteq> j --> zgcd (mf i) (mf j) = 1))"
    8.40 -
    8.41 -definition
    8.42 -  km_cond :: "nat => (nat => int) => (nat => int) => bool" where
    8.43 -  "km_cond n kf mf = (\<forall>i. i \<le> n --> zgcd (kf i) (mf i) = 1)"
    8.44 -
    8.45 -definition
    8.46 -  lincong_sol ::
    8.47 -    "nat => (nat => int) => (nat => int) => (nat => int) => int => bool" where
    8.48 -  "lincong_sol n kf bf mf x = (\<forall>i. i \<le> n --> zcong (kf i * x) (bf i) (mf i))"
    8.49 -
    8.50 -definition
    8.51 -  mhf :: "(nat => int) => nat => nat => int" where
    8.52 -  "mhf mf n i =
    8.53 -    (if i = 0 then funprod mf (Suc 0) (n - Suc 0)
    8.54 -     else if i = n then funprod mf 0 (n - Suc 0)
    8.55 -     else funprod mf 0 (i - Suc 0) * funprod mf (Suc i) (n - Suc 0 - i))"
    8.56 -
    8.57 -definition
    8.58 -  xilin_sol ::
    8.59 -    "nat => nat => (nat => int) => (nat => int) => (nat => int) => int" where
    8.60 -  "xilin_sol i n kf bf mf =
    8.61 -    (if 0 < n \<and> i \<le> n \<and> m_cond n mf \<and> km_cond n kf mf then
    8.62 -        (SOME x. 0 \<le> x \<and> x < mf i \<and> zcong (kf i * mhf mf n i * x) (bf i) (mf i))
    8.63 -     else 0)"
    8.64 -
    8.65 -definition
    8.66 -  x_sol :: "nat => (nat => int) => (nat => int) => (nat => int) => int" where
    8.67 -  "x_sol n kf bf mf = funsum (\<lambda>i. xilin_sol i n kf bf mf * mhf mf n i) 0 n"
    8.68 -
    8.69 -
    8.70 -text \<open>\medskip @{term funprod} and @{term funsum}\<close>
    8.71 -
    8.72 -lemma funprod_pos: "(\<forall>i. i \<le> n --> 0 < mf i) ==> 0 < funprod mf 0 n"
    8.73 -by (induct n) auto
    8.74 -
    8.75 -lemma funprod_zgcd [rule_format (no_asm)]:
    8.76 -  "(\<forall>i. k \<le> i \<and> i \<le> k + l --> zgcd (mf i) (mf m) = 1) -->
    8.77 -    zgcd (funprod mf k l) (mf m) = 1"
    8.78 -  apply (induct l)
    8.79 -   apply simp_all
    8.80 -  apply (rule impI)+
    8.81 -  apply (subst zgcd_zmult_cancel)
    8.82 -  apply auto
    8.83 -  done
    8.84 -
    8.85 -lemma funprod_zdvd [rule_format]:
    8.86 -    "k \<le> i --> i \<le> k + l --> mf i dvd funprod mf k l"
    8.87 -  apply (induct l)
    8.88 -   apply auto
    8.89 -  apply (subgoal_tac "i = Suc (k + l)")
    8.90 -   apply (simp_all (no_asm_simp))
    8.91 -  done
    8.92 -
    8.93 -lemma funsum_mod:
    8.94 -    "funsum f k l mod m = funsum (\<lambda>i. (f i) mod m) k l mod m"
    8.95 -  apply (induct l)
    8.96 -   apply auto
    8.97 -  apply (rule trans)
    8.98 -   apply (rule mod_add_eq)
    8.99 -  apply simp
   8.100 -  apply (rule mod_add_right_eq [symmetric])
   8.101 -  done
   8.102 -
   8.103 -lemma funsum_zero [rule_format (no_asm)]:
   8.104 -    "(\<forall>i. k \<le> i \<and> i \<le> k + l --> f i = 0) --> (funsum f k l) = 0"
   8.105 -  apply (induct l)
   8.106 -   apply auto
   8.107 -  done
   8.108 -
   8.109 -lemma funsum_oneelem [rule_format (no_asm)]:
   8.110 -  "k \<le> j --> j \<le> k + l -->
   8.111 -    (\<forall>i. k \<le> i \<and> i \<le> k + l \<and> i \<noteq> j --> f i = 0) -->
   8.112 -    funsum f k l = f j"
   8.113 -  apply (induct l)
   8.114 -   prefer 2
   8.115 -   apply clarify
   8.116 -   defer
   8.117 -   apply clarify
   8.118 -   apply (subgoal_tac "k = j")
   8.119 -    apply (simp_all (no_asm_simp))
   8.120 -  apply (case_tac "Suc (k + l) = j")
   8.121 -   apply (subgoal_tac "funsum f k l = 0")
   8.122 -    apply (rule_tac [2] funsum_zero)
   8.123 -    apply (subgoal_tac [3] "f (Suc (k + l)) = 0")
   8.124 -     apply (subgoal_tac [3] "j \<le> k + l")
   8.125 -      prefer 4
   8.126 -      apply arith
   8.127 -     apply auto
   8.128 -  done
   8.129 -
   8.130 -
   8.131 -subsection \<open>Chinese: uniqueness\<close>
   8.132 -
   8.133 -lemma zcong_funprod_aux:
   8.134 -  "m_cond n mf ==> km_cond n kf mf
   8.135 -    ==> lincong_sol n kf bf mf x ==> lincong_sol n kf bf mf y
   8.136 -    ==> [x = y] (mod mf n)"
   8.137 -  apply (unfold m_cond_def km_cond_def lincong_sol_def)
   8.138 -  apply (rule iffD1)
   8.139 -   apply (rule_tac k = "kf n" in zcong_cancel2)
   8.140 -    apply (rule_tac [3] b = "bf n" in zcong_trans)
   8.141 -     prefer 4
   8.142 -     apply (subst zcong_sym)
   8.143 -     defer
   8.144 -     apply (rule order_less_imp_le)
   8.145 -     apply simp_all
   8.146 -  done
   8.147 -
   8.148 -lemma zcong_funprod [rule_format]:
   8.149 -  "m_cond n mf --> km_cond n kf mf -->
   8.150 -    lincong_sol n kf bf mf x --> lincong_sol n kf bf mf y -->
   8.151 -    [x = y] (mod funprod mf 0 n)"
   8.152 -  apply (induct n)
   8.153 -   apply (simp_all (no_asm))
   8.154 -   apply (blast intro: zcong_funprod_aux)
   8.155 -  apply (rule impI)+
   8.156 -  apply (rule zcong_zgcd_zmult_zmod)
   8.157 -    apply (blast intro: zcong_funprod_aux)
   8.158 -    prefer 2
   8.159 -    apply (subst zgcd_commute)
   8.160 -    apply (rule funprod_zgcd)
   8.161 -   apply (auto simp add: m_cond_def km_cond_def lincong_sol_def)
   8.162 -  done
   8.163 -
   8.164 -
   8.165 -subsection \<open>Chinese: existence\<close>
   8.166 -
   8.167 -lemma unique_xi_sol:
   8.168 -  "0 < n ==> i \<le> n ==> m_cond n mf ==> km_cond n kf mf
   8.169 -    ==> \<exists>!x. 0 \<le> x \<and> x < mf i \<and> [kf i * mhf mf n i * x = bf i] (mod mf i)"
   8.170 -  apply (rule zcong_lineq_unique)
   8.171 -   apply (tactic \<open>stac @{context} @{thm zgcd_zmult_cancel} 2\<close>)
   8.172 -    apply (unfold m_cond_def km_cond_def mhf_def)
   8.173 -    apply (simp_all (no_asm_simp))
   8.174 -  apply safe
   8.175 -    apply (tactic \<open>stac @{context} @{thm zgcd_zmult_cancel} 3\<close>)
   8.176 -     apply (rule_tac [!] funprod_zgcd)
   8.177 -     apply safe
   8.178 -     apply simp_all
   8.179 -   apply (subgoal_tac "ia<n")
   8.180 -    prefer 2
   8.181 -    apply arith
   8.182 -   apply (case_tac [2] i)
   8.183 -    apply simp_all
   8.184 -  done
   8.185 -
   8.186 -lemma x_sol_lin_aux:
   8.187 -    "0 < n ==> i \<le> n ==> j \<le> n ==> j \<noteq> i ==> mf j dvd mhf mf n i"
   8.188 -  apply (unfold mhf_def)
   8.189 -  apply (case_tac "i = 0")
   8.190 -   apply (case_tac [2] "i = n")
   8.191 -    apply (simp_all (no_asm_simp))
   8.192 -    apply (case_tac [3] "j < i")
   8.193 -     apply (rule_tac [3] dvd_mult2)
   8.194 -     apply (rule_tac [4] dvd_mult)
   8.195 -     apply (rule_tac [!] funprod_zdvd)
   8.196 -     apply arith
   8.197 -     apply arith
   8.198 -     apply arith
   8.199 -     apply arith
   8.200 -     apply arith
   8.201 -     apply arith
   8.202 -     apply arith
   8.203 -     apply arith
   8.204 -  done
   8.205 -
   8.206 -lemma x_sol_lin:
   8.207 -  "0 < n ==> i \<le> n
   8.208 -    ==> x_sol n kf bf mf mod mf i =
   8.209 -      xilin_sol i n kf bf mf * mhf mf n i mod mf i"
   8.210 -  apply (unfold x_sol_def)
   8.211 -  apply (subst funsum_mod)
   8.212 -  apply (subst funsum_oneelem)
   8.213 -     apply auto
   8.214 -  apply (subst dvd_eq_mod_eq_0 [symmetric])
   8.215 -  apply (rule dvd_mult)
   8.216 -  apply (rule x_sol_lin_aux)
   8.217 -  apply auto
   8.218 -  done
   8.219 -
   8.220 -
   8.221 -subsection \<open>Chinese\<close>
   8.222 -
   8.223 -lemma chinese_remainder:
   8.224 -  "0 < n ==> m_cond n mf ==> km_cond n kf mf
   8.225 -    ==> \<exists>!x. 0 \<le> x \<and> x < funprod mf 0 n \<and> lincong_sol n kf bf mf x"
   8.226 -  apply safe
   8.227 -   apply (rule_tac [2] m = "funprod mf 0 n" in zcong_zless_imp_eq)
   8.228 -       apply (rule_tac [6] zcong_funprod)
   8.229 -          apply auto
   8.230 -  apply (rule_tac x = "x_sol n kf bf mf mod funprod mf 0 n" in exI)
   8.231 -  apply (unfold lincong_sol_def)
   8.232 -  apply safe
   8.233 -    apply (tactic \<open>stac @{context} @{thm zcong_zmod} 3\<close>)
   8.234 -    apply (tactic \<open>stac @{context} @{thm mod_mult_eq} 3\<close>)
   8.235 -    apply (tactic \<open>stac @{context} @{thm mod_mod_cancel} 3\<close>)
   8.236 -      apply (tactic \<open>stac @{context} @{thm x_sol_lin} 4\<close>)
   8.237 -        apply (tactic \<open>stac @{context} (@{thm mod_mult_eq} RS sym) 6\<close>)
   8.238 -        apply (tactic \<open>stac @{context} (@{thm zcong_zmod} RS sym) 6\<close>)
   8.239 -        apply (subgoal_tac [6]
   8.240 -          "0 \<le> xilin_sol i n kf bf mf \<and> xilin_sol i n kf bf mf < mf i
   8.241 -          \<and> [kf i * mhf mf n i * xilin_sol i n kf bf mf = bf i] (mod mf i)")
   8.242 -         prefer 6
   8.243 -         apply (simp add: ac_simps)
   8.244 -        apply (unfold xilin_sol_def)
   8.245 -        apply (tactic \<open>asm_simp_tac @{context} 6\<close>)
   8.246 -        apply (rule_tac [6] ex1_implies_ex [THEN someI_ex])
   8.247 -        apply (rule_tac [6] unique_xi_sol)
   8.248 -           apply (rule_tac [3] funprod_zdvd)
   8.249 -            apply (unfold m_cond_def)
   8.250 -            apply (rule funprod_pos [THEN pos_mod_sign])
   8.251 -            apply (rule_tac [2] funprod_pos [THEN pos_mod_bound])
   8.252 -            apply auto
   8.253 -  done
   8.254 -
   8.255 -end
     9.1 --- a/src/HOL/Old_Number_Theory/Euler.thy	Tue Oct 18 07:04:08 2016 +0200
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,303 +0,0 @@
     9.4 -(*  Title:      HOL/Old_Number_Theory/Euler.thy
     9.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
     9.6 -*)
     9.7 -
     9.8 -section \<open>Euler's criterion\<close>
     9.9 -
    9.10 -theory Euler
    9.11 -imports Residues EvenOdd
    9.12 -begin
    9.13 -
    9.14 -definition MultInvPair :: "int => int => int => int set"
    9.15 -  where "MultInvPair a p j = {StandardRes p j, StandardRes p (a * (MultInv p j))}"
    9.16 -
    9.17 -definition SetS :: "int => int => int set set"
    9.18 -  where "SetS a p = MultInvPair a p ` SRStar p"
    9.19 -
    9.20 -
    9.21 -subsection \<open>Property for MultInvPair\<close>
    9.22 -
    9.23 -lemma MultInvPair_prop1a:
    9.24 -  "[| zprime p; 2 < p; ~([a = 0](mod p));
    9.25 -      X \<in> (SetS a p); Y \<in> (SetS a p);
    9.26 -      ~((X \<inter> Y) = {}) |] ==> X = Y"
    9.27 -  apply (auto simp add: SetS_def)
    9.28 -  apply (drule StandardRes_SRStar_prop1a)+ defer 1
    9.29 -  apply (drule StandardRes_SRStar_prop1a)+
    9.30 -  apply (auto simp add: MultInvPair_def StandardRes_prop2 zcong_sym)
    9.31 -  apply (drule notE, rule MultInv_zcong_prop1, auto)[]
    9.32 -  apply (drule notE, rule MultInv_zcong_prop2, auto simp add: zcong_sym)[]
    9.33 -  apply (drule MultInv_zcong_prop2, auto simp add: zcong_sym)[]
    9.34 -  apply (drule MultInv_zcong_prop3, auto simp add: zcong_sym)[]
    9.35 -  apply (drule MultInv_zcong_prop1, auto)[]
    9.36 -  apply (drule MultInv_zcong_prop2, auto simp add: zcong_sym)[]
    9.37 -  apply (drule MultInv_zcong_prop2, auto simp add: zcong_sym)[]
    9.38 -  apply (drule MultInv_zcong_prop3, auto simp add: zcong_sym)[]
    9.39 -  done
    9.40 -
    9.41 -lemma MultInvPair_prop1b:
    9.42 -  "[| zprime p; 2 < p; ~([a = 0](mod p));
    9.43 -      X \<in> (SetS a p); Y \<in> (SetS a p);
    9.44 -      X \<noteq> Y |] ==> X \<inter> Y = {}"
    9.45 -  apply (rule notnotD)
    9.46 -  apply (rule notI)
    9.47 -  apply (drule MultInvPair_prop1a, auto)
    9.48 -  done
    9.49 -
    9.50 -lemma MultInvPair_prop1c: "[| zprime p; 2 < p; ~([a = 0](mod p)) |] ==>  
    9.51 -    \<forall>X \<in> SetS a p. \<forall>Y \<in> SetS a p. X \<noteq> Y --> X\<inter>Y = {}"
    9.52 -  by (auto simp add: MultInvPair_prop1b)
    9.53 -
    9.54 -lemma MultInvPair_prop2: "[| zprime p; 2 < p; ~([a = 0](mod p)) |] ==> 
    9.55 -                          \<Union>(SetS a p) = SRStar p"
    9.56 -  apply (auto simp add: SetS_def MultInvPair_def StandardRes_SRStar_prop4 
    9.57 -    SRStar_mult_prop2)
    9.58 -  apply (frule StandardRes_SRStar_prop3)
    9.59 -  apply (rule bexI, auto)
    9.60 -  done
    9.61 -
    9.62 -lemma MultInvPair_distinct:
    9.63 -  assumes "zprime p" and "2 < p" and
    9.64 -    "~([a = 0] (mod p))" and
    9.65 -    "~([j = 0] (mod p))" and
    9.66 -    "~(QuadRes p a)"
    9.67 -  shows "~([j = a * MultInv p j] (mod p))"
    9.68 -proof
    9.69 -  assume "[j = a * MultInv p j] (mod p)"
    9.70 -  then have "[j * j = (a * MultInv p j) * j] (mod p)"
    9.71 -    by (auto simp add: zcong_scalar)
    9.72 -  then have a:"[j * j = a * (MultInv p j * j)] (mod p)"
    9.73 -    by (auto simp add: ac_simps)
    9.74 -  have "[j * j = a] (mod p)"
    9.75 -  proof -
    9.76 -    from assms(1,2,4) have "[MultInv p j * j = 1] (mod p)"
    9.77 -      by (simp add: MultInv_prop2a)
    9.78 -    from this and a show ?thesis
    9.79 -      by (auto simp add: zcong_zmult_prop2)
    9.80 -  qed
    9.81 -  then have "[j\<^sup>2 = a] (mod p)" by (simp add: power2_eq_square)
    9.82 -  with assms show False by (simp add: QuadRes_def)
    9.83 -qed
    9.84 -
    9.85 -lemma MultInvPair_card_two: "[| zprime p; 2 < p; ~([a = 0] (mod p)); 
    9.86 -                                ~(QuadRes p a); ~([j = 0] (mod p)) |]  ==> 
    9.87 -                             card (MultInvPair a p j) = 2"
    9.88 -  apply (auto simp add: MultInvPair_def)
    9.89 -  apply (subgoal_tac "~ (StandardRes p j = StandardRes p (a * MultInv p j))")
    9.90 -  apply auto
    9.91 -  apply (metis MultInvPair_distinct StandardRes_def aux)
    9.92 -  done
    9.93 -
    9.94 -
    9.95 -subsection \<open>Properties of SetS\<close>
    9.96 -
    9.97 -lemma SetS_finite: "2 < p ==> finite (SetS a p)"
    9.98 -  by (auto simp add: SetS_def SRStar_finite [of p])
    9.99 -
   9.100 -lemma SetS_elems_finite: "\<forall>X \<in> SetS a p. finite X"
   9.101 -  by (auto simp add: SetS_def MultInvPair_def)
   9.102 -
   9.103 -lemma SetS_elems_card: "[| zprime p; 2 < p; ~([a = 0] (mod p)); 
   9.104 -                        ~(QuadRes p a) |]  ==>
   9.105 -                        \<forall>X \<in> SetS a p. card X = 2"
   9.106 -  apply (auto simp add: SetS_def)
   9.107 -  apply (frule StandardRes_SRStar_prop1a)
   9.108 -  apply (rule MultInvPair_card_two, auto)
   9.109 -  done
   9.110 -
   9.111 -lemma Union_SetS_finite: "2 < p ==> finite (\<Union>(SetS a p))"
   9.112 -  by (auto simp add: SetS_finite SetS_elems_finite)
   9.113 -
   9.114 -lemma card_sum_aux: "[| finite S; \<forall>X \<in> S. finite (X::int set); 
   9.115 -    \<forall>X \<in> S. card X = n |] ==> sum card S = sum (%x. n) S"
   9.116 -  by (induct set: finite) auto
   9.117 -
   9.118 -lemma SetS_card:
   9.119 -  assumes "zprime p" and "2 < p" and "~([a = 0] (mod p))" and "~(QuadRes p a)"
   9.120 -  shows "int(card(SetS a p)) = (p - 1) div 2"
   9.121 -proof -
   9.122 -  have "(p - 1) = 2 * int(card(SetS a p))"
   9.123 -  proof -
   9.124 -    have "p - 1 = int(card(\<Union>(SetS a p)))"
   9.125 -      by (auto simp add: assms MultInvPair_prop2 SRStar_card)
   9.126 -    also have "... = int (sum card (SetS a p))"
   9.127 -      by (auto simp add: assms SetS_finite SetS_elems_finite
   9.128 -        MultInvPair_prop1c [of p a] card_Union_disjoint)
   9.129 -    also have "... = int(sum (%x.2) (SetS a p))"
   9.130 -      using assms by (auto simp add: SetS_elems_card SetS_finite SetS_elems_finite
   9.131 -        card_sum_aux simp del: sum_constant)
   9.132 -    also have "... = 2 * int(card( SetS a p))"
   9.133 -      by (auto simp add: assms SetS_finite sum_const2)
   9.134 -    finally show ?thesis .
   9.135 -  qed
   9.136 -  then show ?thesis by auto
   9.137 -qed
   9.138 -
   9.139 -lemma SetS_prod_prop: "[| zprime p; 2 < p; ~([a = 0] (mod p));
   9.140 -                              ~(QuadRes p a); x \<in> (SetS a p) |] ==> 
   9.141 -                          [\<Prod>x = a] (mod p)"
   9.142 -  apply (auto simp add: SetS_def MultInvPair_def)
   9.143 -  apply (frule StandardRes_SRStar_prop1a)
   9.144 -  apply hypsubst_thin
   9.145 -  apply (subgoal_tac "StandardRes p x \<noteq> StandardRes p (a * MultInv p x)")
   9.146 -  apply (auto simp add: StandardRes_prop2 MultInvPair_distinct)
   9.147 -  apply (frule_tac m = p and x = x and y = "(a * MultInv p x)" in 
   9.148 -    StandardRes_prop4)
   9.149 -  apply (subgoal_tac "[x * (a * MultInv p x) = a * (x * MultInv p x)] (mod p)")
   9.150 -  apply (drule_tac a = "StandardRes p x * StandardRes p (a * MultInv p x)" and
   9.151 -                   b = "x * (a * MultInv p x)" and
   9.152 -                   c = "a * (x * MultInv p x)" in  zcong_trans, force)
   9.153 -  apply (frule_tac p = p and x = x in MultInv_prop2, auto)
   9.154 -apply (metis StandardRes_SRStar_prop3 mult_1_right mult.commute zcong_sym zcong_zmult_prop1)
   9.155 -  apply (auto simp add: ac_simps)
   9.156 -  done
   9.157 -
   9.158 -lemma aux1: "[| 0 < x; (x::int) < a; x \<noteq> (a - 1) |] ==> x < a - 1"
   9.159 -  by arith
   9.160 -
   9.161 -lemma aux2: "[| (a::int) < c; b < c |] ==> (a \<le> b | b \<le> a)"
   9.162 -  by auto
   9.163 -
   9.164 -lemma d22set_induct_old: "(\<And>a::int. 1 < a \<longrightarrow> P (a - 1) \<Longrightarrow> P a) \<Longrightarrow> P x"
   9.165 -using d22set.induct by blast
   9.166 -
   9.167 -lemma SRStar_d22set_prop: "2 < p \<Longrightarrow> (SRStar p) = {1} \<union> (d22set (p - 1))"
   9.168 -  apply (induct p rule: d22set_induct_old)
   9.169 -  apply auto
   9.170 -  apply (simp add: SRStar_def d22set.simps)
   9.171 -  apply (simp add: SRStar_def d22set.simps, clarify)
   9.172 -  apply (frule aux1)
   9.173 -  apply (frule aux2, auto)
   9.174 -  apply (simp_all add: SRStar_def)
   9.175 -  apply (simp add: d22set.simps)
   9.176 -  apply (frule d22set_le)
   9.177 -  apply (frule d22set_g_1, auto)
   9.178 -  done
   9.179 -
   9.180 -lemma Union_SetS_prod_prop1:
   9.181 -  assumes "zprime p" and "2 < p" and "~([a = 0] (mod p))" and
   9.182 -    "~(QuadRes p a)"
   9.183 -  shows "[\<Prod>(\<Union>(SetS a p)) = a ^ nat ((p - 1) div 2)] (mod p)"
   9.184 -proof -
   9.185 -  from assms have "[\<Prod>(\<Union>(SetS a p)) = prod (prod (%x. x)) (SetS a p)] (mod p)"
   9.186 -    by (auto simp add: SetS_finite SetS_elems_finite
   9.187 -      MultInvPair_prop1c prod.Union_disjoint)
   9.188 -  also have "[prod (prod (%x. x)) (SetS a p) = 
   9.189 -      prod (%x. a) (SetS a p)] (mod p)"
   9.190 -    by (rule prod_same_function_zcong)
   9.191 -      (auto simp add: assms SetS_prod_prop SetS_finite)
   9.192 -  also (zcong_trans) have "[prod (%x. a) (SetS a p) = 
   9.193 -      a^(card (SetS a p))] (mod p)"
   9.194 -    by (auto simp add: assms SetS_finite prod_constant)
   9.195 -  finally (zcong_trans) show ?thesis
   9.196 -    apply (rule zcong_trans)
   9.197 -    apply (subgoal_tac "card(SetS a p) = nat((p - 1) div 2)", auto)
   9.198 -    apply (subgoal_tac "nat(int(card(SetS a p))) = nat((p - 1) div 2)", force)
   9.199 -    apply (auto simp add: assms SetS_card)
   9.200 -    done
   9.201 -qed
   9.202 -
   9.203 -lemma Union_SetS_prod_prop2:
   9.204 -  assumes "zprime p" and "2 < p" and "~([a = 0](mod p))"
   9.205 -  shows "\<Prod>(\<Union>(SetS a p)) = zfact (p - 1)"
   9.206 -proof -
   9.207 -  from assms have "\<Prod>(\<Union>(SetS a p)) = \<Prod>(SRStar p)"
   9.208 -    by (auto simp add: MultInvPair_prop2)
   9.209 -  also have "... = \<Prod>({1} \<union> (d22set (p - 1)))"
   9.210 -    by (auto simp add: assms SRStar_d22set_prop)
   9.211 -  also have "... = zfact(p - 1)"
   9.212 -  proof -
   9.213 -    have "~(1 \<in> d22set (p - 1)) & finite( d22set (p - 1))"
   9.214 -      by (metis d22set_fin d22set_g_1 linorder_neq_iff)
   9.215 -    then have "\<Prod>({1} \<union> (d22set (p - 1))) = \<Prod>(d22set (p - 1))"
   9.216 -      by auto
   9.217 -    then show ?thesis
   9.218 -      by (auto simp add: d22set_prod_zfact)
   9.219 -  qed
   9.220 -  finally show ?thesis .
   9.221 -qed
   9.222 -
   9.223 -lemma zfact_prop: "[| zprime p; 2 < p; ~([a = 0] (mod p)); ~(QuadRes p a) |] ==>
   9.224 -                   [zfact (p - 1) = a ^ nat ((p - 1) div 2)] (mod p)"
   9.225 -  apply (frule Union_SetS_prod_prop1) 
   9.226 -  apply (auto simp add: Union_SetS_prod_prop2)
   9.227 -  done
   9.228 -
   9.229 -text \<open>\medskip Prove the first part of Euler's Criterion:\<close>
   9.230 -
   9.231 -lemma Euler_part1: "[| 2 < p; zprime p; ~([x = 0](mod p)); 
   9.232 -    ~(QuadRes p x) |] ==> 
   9.233 -      [x^(nat (((p) - 1) div 2)) = -1](mod p)"
   9.234 -  by (metis Wilson_Russ zcong_sym zcong_trans zfact_prop)
   9.235 -
   9.236 -text \<open>\medskip Prove another part of Euler Criterion:\<close>
   9.237 -
   9.238 -lemma aux_1: "0 < p ==> (a::int) ^ nat (p) = a * a ^ (nat (p) - 1)"
   9.239 -proof -
   9.240 -  assume "0 < p"
   9.241 -  then have "a ^ (nat p) =  a ^ (1 + (nat p - 1))"
   9.242 -    by (auto simp add: diff_add_assoc)
   9.243 -  also have "... = (a ^ 1) * a ^ (nat(p) - 1)"
   9.244 -    by (simp only: power_add)
   9.245 -  also have "... = a * a ^ (nat(p) - 1)"
   9.246 -    by auto
   9.247 -  finally show ?thesis .
   9.248 -qed
   9.249 -
   9.250 -lemma aux_2: "[| (2::int) < p; p \<in> zOdd |] ==> 0 < ((p - 1) div 2)"
   9.251 -proof -
   9.252 -  assume "2 < p" and "p \<in> zOdd"
   9.253 -  then have "(p - 1):zEven"
   9.254 -    by (auto simp add: zEven_def zOdd_def)
   9.255 -  then have aux_1: "2 * ((p - 1) div 2) = (p - 1)"
   9.256 -    by (auto simp add: even_div_2_prop2)
   9.257 -  with \<open>2 < p\<close> have "1 < (p - 1)"
   9.258 -    by auto
   9.259 -  then have " 1 < (2 * ((p - 1) div 2))"
   9.260 -    by (auto simp add: aux_1)
   9.261 -  then have "0 < (2 * ((p - 1) div 2)) div 2"
   9.262 -    by auto
   9.263 -  then show ?thesis by auto
   9.264 -qed
   9.265 -
   9.266 -lemma Euler_part2:
   9.267 -    "[| 2 < p; zprime p; [a = 0] (mod p) |] ==> [0 = a ^ nat ((p - 1) div 2)] (mod p)"
   9.268 -  apply (frule zprime_zOdd_eq_grt_2)
   9.269 -  apply (frule aux_2, auto)
   9.270 -  apply (frule_tac a = a in aux_1, auto)
   9.271 -  apply (frule zcong_zmult_prop1, auto)
   9.272 -  done
   9.273 -
   9.274 -text \<open>\medskip Prove the final part of Euler's Criterion:\<close>
   9.275 -
   9.276 -lemma aux__1: "[| ~([x = 0] (mod p)); [y\<^sup>2 = x] (mod p)|] ==> ~(p dvd y)"
   9.277 -  by (metis dvdI power2_eq_square zcong_sym zcong_trans zcong_zero_equiv_div dvd_trans)
   9.278 -
   9.279 -lemma aux__2: "2 * nat((p - 1) div 2) =  nat (2 * ((p - 1) div 2))"
   9.280 -  by (auto simp add: nat_mult_distrib)
   9.281 -
   9.282 -lemma Euler_part3: "[| 2 < p; zprime p; ~([x = 0](mod p)); QuadRes p x |] ==> 
   9.283 -                      [x^(nat (((p) - 1) div 2)) = 1](mod p)"
   9.284 -  apply (subgoal_tac "p \<in> zOdd")
   9.285 -  apply (auto simp add: QuadRes_def)
   9.286 -   prefer 2 
   9.287 -   apply (metis zprime_zOdd_eq_grt_2)
   9.288 -  apply (frule aux__1, auto)
   9.289 -  apply (drule_tac z = "nat ((p - 1) div 2)" in zcong_zpower)
   9.290 -  apply (auto simp add: power_mult [symmetric]) 
   9.291 -  apply (rule zcong_trans)
   9.292 -  apply (auto simp add: zcong_sym [of "x ^ nat ((p - 1) div 2)"])
   9.293 -  apply (metis Little_Fermat even_div_2_prop2 odd_minus_one_even mult_1 aux__2)
   9.294 -  done
   9.295 -
   9.296 -
   9.297 -text \<open>\medskip Finally show Euler's Criterion:\<close>
   9.298 -
   9.299 -theorem Euler_Criterion: "[| 2 < p; zprime p |] ==> [(Legendre a p) =
   9.300 -    a^(nat (((p) - 1) div 2))] (mod p)"
   9.301 -  apply (auto simp add: Legendre_def Euler_part2)
   9.302 -  apply (frule Euler_part3, auto simp add: zcong_sym)[]
   9.303 -  apply (frule Euler_part1, auto simp add: zcong_sym)[]
   9.304 -  done
   9.305 -
   9.306 -end
    10.1 --- a/src/HOL/Old_Number_Theory/EulerFermat.thy	Tue Oct 18 07:04:08 2016 +0200
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,332 +0,0 @@
    10.4 -(*  Title:      HOL/Old_Number_Theory/EulerFermat.thy
    10.5 -    Author:     Thomas M. Rasmussen
    10.6 -    Copyright   2000  University of Cambridge
    10.7 -*)
    10.8 -
    10.9 -section \<open>Fermat's Little Theorem extended to Euler's Totient function\<close>
   10.10 -
   10.11 -theory EulerFermat
   10.12 -imports BijectionRel IntFact
   10.13 -begin
   10.14 -
   10.15 -text \<open>
   10.16 -  Fermat's Little Theorem extended to Euler's Totient function. More
   10.17 -  abstract approach than Boyer-Moore (which seems necessary to achieve
   10.18 -  the extended version).
   10.19 -\<close>
   10.20 -
   10.21 -
   10.22 -subsection \<open>Definitions and lemmas\<close>
   10.23 -
   10.24 -inductive_set RsetR :: "int => int set set" for m :: int
   10.25 -where
   10.26 -  empty [simp]: "{} \<in> RsetR m"
   10.27 -| insert: "A \<in> RsetR m ==> zgcd a m = 1 ==>
   10.28 -    \<forall>a'. a' \<in> A --> \<not> zcong a a' m ==> insert a A \<in> RsetR m"
   10.29 -
   10.30 -fun BnorRset :: "int \<Rightarrow> int => int set" where
   10.31 -  "BnorRset a m =
   10.32 -   (if 0 < a then
   10.33 -    let na = BnorRset (a - 1) m
   10.34 -    in (if zgcd a m = 1 then insert a na else na)
   10.35 -    else {})"
   10.36 -
   10.37 -definition norRRset :: "int => int set"
   10.38 -  where "norRRset m = BnorRset (m - 1) m"
   10.39 -
   10.40 -definition noXRRset :: "int => int => int set"
   10.41 -  where "noXRRset m x = (\<lambda>a. a * x) ` norRRset m"
   10.42 -
   10.43 -definition phi :: "int => nat"
   10.44 -  where "phi m = card (norRRset m)"
   10.45 -
   10.46 -definition is_RRset :: "int set => int => bool"
   10.47 -  where "is_RRset A m = (A \<in> RsetR m \<and> card A = phi m)"
   10.48 -
   10.49 -definition RRset2norRR :: "int set => int => int => int"
   10.50 -  where
   10.51 -    "RRset2norRR A m a =
   10.52 -       (if 1 < m \<and> is_RRset A m \<and> a \<in> A then
   10.53 -          SOME b. zcong a b m \<and> b \<in> norRRset m
   10.54 -        else 0)"
   10.55 -
   10.56 -definition zcongm :: "int => int => int => bool"
   10.57 -  where "zcongm m = (\<lambda>a b. zcong a b m)"
   10.58 -
   10.59 -lemma abs_eq_1_iff [iff]: "(\<bar>z\<bar> = (1::int)) = (z = 1 \<or> z = -1)"
   10.60 -  \<comment> \<open>LCP: not sure why this lemma is needed now\<close>
   10.61 -  by (auto simp add: abs_if)
   10.62 -
   10.63 -
   10.64 -text \<open>\medskip \<open>norRRset\<close>\<close>
   10.65 -
   10.66 -declare BnorRset.simps [simp del]
   10.67 -
   10.68 -lemma BnorRset_induct:
   10.69 -  assumes "!!a m. P {} a m"
   10.70 -    and "!!a m :: int. 0 < a ==> P (BnorRset (a - 1) m) (a - 1) m
   10.71 -      ==> P (BnorRset a m) a m"
   10.72 -  shows "P (BnorRset u v) u v"
   10.73 -  apply (rule BnorRset.induct)
   10.74 -   apply (case_tac "0 < a")
   10.75 -    apply (rule_tac assms)
   10.76 -     apply simp_all
   10.77 -   apply (simp_all add: BnorRset.simps assms)
   10.78 -  done
   10.79 -
   10.80 -lemma Bnor_mem_zle [rule_format]: "b \<in> BnorRset a m \<longrightarrow> b \<le> a"
   10.81 -  apply (induct a m rule: BnorRset_induct)
   10.82 -   apply simp
   10.83 -  apply (subst BnorRset.simps)
   10.84 -   apply (unfold Let_def, auto)
   10.85 -  done
   10.86 -
   10.87 -lemma Bnor_mem_zle_swap: "a < b ==> b \<notin> BnorRset a m"
   10.88 -  by (auto dest: Bnor_mem_zle)
   10.89 -
   10.90 -lemma Bnor_mem_zg [rule_format]: "b \<in> BnorRset a m --> 0 < b"
   10.91 -  apply (induct a m rule: BnorRset_induct)
   10.92 -   prefer 2
   10.93 -   apply (subst BnorRset.simps)
   10.94 -   apply (unfold Let_def, auto)
   10.95 -  done
   10.96 -
   10.97 -lemma Bnor_mem_if [rule_format]:
   10.98 -    "zgcd b m = 1 --> 0 < b --> b \<le> a --> b \<in> BnorRset a m"
   10.99 -  apply (induct a m rule: BnorRset.induct, auto)
  10.100 -   apply (subst BnorRset.simps)
  10.101 -   defer
  10.102 -   apply (subst BnorRset.simps)
  10.103 -   apply (unfold Let_def, auto)
  10.104 -  done
  10.105 -
  10.106 -lemma Bnor_in_RsetR [rule_format]: "a < m --> BnorRset a m \<in> RsetR m"
  10.107 -  apply (induct a m rule: BnorRset_induct, simp)
  10.108 -  apply (subst BnorRset.simps)
  10.109 -  apply (unfold Let_def, auto)
  10.110 -  apply (rule RsetR.insert)
  10.111 -    apply (rule_tac [3] allI)
  10.112 -    apply (rule_tac [3] impI)
  10.113 -    apply (rule_tac [3] zcong_not)
  10.114 -       apply (subgoal_tac [6] "a' \<le> a - 1")
  10.115 -        apply (rule_tac [7] Bnor_mem_zle)
  10.116 -        apply (rule_tac [5] Bnor_mem_zg, auto)
  10.117 -  done
  10.118 -
  10.119 -lemma Bnor_fin: "finite (BnorRset a m)"
  10.120 -  apply (induct a m rule: BnorRset_induct)
  10.121 -   prefer 2
  10.122 -   apply (subst BnorRset.simps)
  10.123 -   apply (unfold Let_def, auto)
  10.124 -  done
  10.125 -
  10.126 -lemma norR_mem_unique_aux: "a \<le> b - 1 ==> a < (b::int)"
  10.127 -  apply auto
  10.128 -  done
  10.129 -
  10.130 -lemma norR_mem_unique:
  10.131 -  "1 < m ==>
  10.132 -    zgcd a m = 1 ==> \<exists>!b. [a = b] (mod m) \<and> b \<in> norRRset m"
  10.133 -  apply (unfold norRRset_def)
  10.134 -  apply (cut_tac a = a and m = m in zcong_zless_unique, auto)
  10.135 -   apply (rule_tac [2] m = m in zcong_zless_imp_eq)
  10.136 -       apply (auto intro: Bnor_mem_zle Bnor_mem_zg zcong_trans
  10.137 -         order_less_imp_le norR_mem_unique_aux simp add: zcong_sym)
  10.138 -  apply (rule_tac x = b in exI, safe)
  10.139 -  apply (rule Bnor_mem_if)
  10.140 -    apply (case_tac [2] "b = 0")
  10.141 -     apply (auto intro: order_less_le [THEN iffD2])
  10.142 -   prefer 2
  10.143 -   apply (simp only: zcong_def)
  10.144 -   apply (subgoal_tac "zgcd a m = m")
  10.145 -    prefer 2
  10.146 -    apply (subst zdvd_iff_zgcd [symmetric])
  10.147 -     apply (rule_tac [4] zgcd_zcong_zgcd)
  10.148 -       apply (simp_all (no_asm_use) add: zcong_sym)
  10.149 -  done
  10.150 -
  10.151 -
  10.152 -text \<open>\medskip @{term noXRRset}\<close>
  10.153 -
  10.154 -lemma RRset_gcd [rule_format]:
  10.155 -    "is_RRset A m ==> a \<in> A --> zgcd a m = 1"
  10.156 -  apply (unfold is_RRset_def)
  10.157 -  apply (rule RsetR.induct, auto)
  10.158 -  done
  10.159 -
  10.160 -lemma RsetR_zmult_mono:
  10.161 -  "A \<in> RsetR m ==>
  10.162 -    0 < m ==> zgcd x m = 1 ==> (\<lambda>a. a * x) ` A \<in> RsetR m"
  10.163 -  apply (erule RsetR.induct, simp_all)
  10.164 -  apply (rule RsetR.insert, auto)
  10.165 -   apply (blast intro: zgcd_zgcd_zmult)
  10.166 -  apply (simp add: zcong_cancel)
  10.167 -  done
  10.168 -
  10.169 -lemma card_nor_eq_noX:
  10.170 -  "0 < m ==>
  10.171 -    zgcd x m = 1 ==> card (noXRRset m x) = card (norRRset m)"
  10.172 -  apply (unfold norRRset_def noXRRset_def)
  10.173 -  apply (rule card_image)
  10.174 -   apply (auto simp add: inj_on_def Bnor_fin)
  10.175 -  apply (simp add: BnorRset.simps)
  10.176 -  done
  10.177 -
  10.178 -lemma noX_is_RRset:
  10.179 -    "0 < m ==> zgcd x m = 1 ==> is_RRset (noXRRset m x) m"
  10.180 -  apply (unfold is_RRset_def phi_def)
  10.181 -  apply (auto simp add: card_nor_eq_noX)
  10.182 -  apply (unfold noXRRset_def norRRset_def)
  10.183 -  apply (rule RsetR_zmult_mono)
  10.184 -    apply (rule Bnor_in_RsetR, simp_all)
  10.185 -  done
  10.186 -
  10.187 -lemma aux_some:
  10.188 -  "1 < m ==> is_RRset A m ==> a \<in> A
  10.189 -    ==> zcong a (SOME b. [a = b] (mod m) \<and> b \<in> norRRset m) m \<and>
  10.190 -      (SOME b. [a = b] (mod m) \<and> b \<in> norRRset m) \<in> norRRset m"
  10.191 -  apply (rule norR_mem_unique [THEN ex1_implies_ex, THEN someI_ex])
  10.192 -   apply (rule_tac [2] RRset_gcd, simp_all)
  10.193 -  done
  10.194 -
  10.195 -lemma RRset2norRR_correct:
  10.196 -  "1 < m ==> is_RRset A m ==> a \<in> A ==>
  10.197 -    [a = RRset2norRR A m a] (mod m) \<and> RRset2norRR A m a \<in> norRRset m"
  10.198 -  apply (unfold RRset2norRR_def, simp)
  10.199 -  apply (rule aux_some, simp_all)
  10.200 -  done
  10.201 -
  10.202 -lemmas RRset2norRR_correct1 = RRset2norRR_correct [THEN conjunct1]
  10.203 -lemmas RRset2norRR_correct2 = RRset2norRR_correct [THEN conjunct2]
  10.204 -
  10.205 -lemma RsetR_fin: "A \<in> RsetR m ==> finite A"
  10.206 -  by (induct set: RsetR) auto
  10.207 -
  10.208 -lemma RRset_zcong_eq [rule_format]:
  10.209 -  "1 < m ==>
  10.210 -    is_RRset A m ==> [a = b] (mod m) ==> a \<in> A --> b \<in> A --> a = b"
  10.211 -  apply (unfold is_RRset_def)
  10.212 -  apply (rule RsetR.induct)
  10.213 -    apply (auto simp add: zcong_sym)
  10.214 -  done
  10.215 -
  10.216 -lemma aux:
  10.217 -  "P (SOME a. P a) ==> Q (SOME a. Q a) ==>
  10.218 -    (SOME a. P a) = (SOME a. Q a) ==> \<exists>a. P a \<and> Q a"
  10.219 -  apply auto
  10.220 -  done
  10.221 -
  10.222 -lemma RRset2norRR_inj:
  10.223 -    "1 < m ==> is_RRset A m ==> inj_on (RRset2norRR A m) A"
  10.224 -  apply (unfold RRset2norRR_def inj_on_def, auto)
  10.225 -  apply (subgoal_tac "\<exists>b. ([x = b] (mod m) \<and> b \<in> norRRset m) \<and>
  10.226 -      ([y = b] (mod m) \<and> b \<in> norRRset m)")
  10.227 -   apply (rule_tac [2] aux)
  10.228 -     apply (rule_tac [3] aux_some)
  10.229 -       apply (rule_tac [2] aux_some)
  10.230 -         apply (rule RRset_zcong_eq, auto)
  10.231 -  apply (rule_tac b = b in zcong_trans)
  10.232 -   apply (simp_all add: zcong_sym)
  10.233 -  done
  10.234 -
  10.235 -lemma RRset2norRR_eq_norR:
  10.236 -    "1 < m ==> is_RRset A m ==> RRset2norRR A m ` A = norRRset m"
  10.237 -  apply (rule card_seteq)
  10.238 -    prefer 3
  10.239 -    apply (subst card_image)
  10.240 -      apply (rule_tac RRset2norRR_inj, auto)
  10.241 -     apply (rule_tac [3] RRset2norRR_correct2, auto)
  10.242 -    apply (unfold is_RRset_def phi_def norRRset_def)
  10.243 -    apply (auto simp add: Bnor_fin)
  10.244 -  done
  10.245 -
  10.246 -
  10.247 -lemma Bnor_prod_power_aux: "a \<notin> A ==> inj f ==> f a \<notin> f ` A"
  10.248 -by (unfold inj_on_def, auto)
  10.249 -
  10.250 -lemma Bnor_prod_power [rule_format]:
  10.251 -  "x \<noteq> 0 ==> a < m --> \<Prod>((\<lambda>a. a * x) ` BnorRset a m) =
  10.252 -      \<Prod>(BnorRset a m) * x^card (BnorRset a m)"
  10.253 -  apply (induct a m rule: BnorRset_induct)
  10.254 -   prefer 2
  10.255 -   apply (simplesubst BnorRset.simps)  \<comment>\<open>multiple redexes\<close>
  10.256 -   apply (unfold Let_def, auto)
  10.257 -  apply (simp add: Bnor_fin Bnor_mem_zle_swap)
  10.258 -  apply (subst prod.insert)
  10.259 -    apply (rule_tac [2] Bnor_prod_power_aux)
  10.260 -     apply (unfold inj_on_def)
  10.261 -     apply (simp_all add: ac_simps Bnor_fin Bnor_mem_zle_swap)
  10.262 -  done
  10.263 -
  10.264 -
  10.265 -subsection \<open>Fermat\<close>
  10.266 -
  10.267 -lemma bijzcong_zcong_prod:
  10.268 -    "(A, B) \<in> bijR (zcongm m) ==> [\<Prod>A = \<Prod>B] (mod m)"
  10.269 -  apply (unfold zcongm_def)
  10.270 -  apply (erule bijR.induct)
  10.271 -   apply (subgoal_tac [2] "a \<notin> A \<and> b \<notin> B \<and> finite A \<and> finite B")
  10.272 -    apply (auto intro: fin_bijRl fin_bijRr zcong_zmult)
  10.273 -  done
  10.274 -
  10.275 -lemma Bnor_prod_zgcd [rule_format]:
  10.276 -    "a < m --> zgcd (\<Prod>(BnorRset a m)) m = 1"
  10.277 -  apply (induct a m rule: BnorRset_induct)
  10.278 -   prefer 2
  10.279 -   apply (subst BnorRset.simps)
  10.280 -   apply (unfold Let_def, auto)
  10.281 -  apply (simp add: Bnor_fin Bnor_mem_zle_swap)
  10.282 -  apply (blast intro: zgcd_zgcd_zmult)
  10.283 -  done
  10.284 -
  10.285 -theorem Euler_Fermat:
  10.286 -    "0 < m ==> zgcd x m = 1 ==> [x^(phi m) = 1] (mod m)"
  10.287 -  apply (unfold norRRset_def phi_def)
  10.288 -  apply (case_tac "x = 0")
  10.289 -   apply (case_tac [2] "m = 1")
  10.290 -    apply (rule_tac [3] iffD1)
  10.291 -     apply (rule_tac [3] k = "\<Prod>(BnorRset (m - 1) m)"
  10.292 -       in zcong_cancel2)
  10.293 -      prefer 5
  10.294 -      apply (subst Bnor_prod_power [symmetric])
  10.295 -        apply (rule_tac [7] Bnor_prod_zgcd, simp_all)
  10.296 -  apply (rule bijzcong_zcong_prod)
  10.297 -  apply (fold norRRset_def, fold noXRRset_def)
  10.298 -  apply (subst RRset2norRR_eq_norR [symmetric])
  10.299 -    apply (rule_tac [3] inj_func_bijR, auto)
  10.300 -     apply (unfold zcongm_def)
  10.301 -     apply (rule_tac [2] RRset2norRR_correct1)
  10.302 -       apply (rule_tac [5] RRset2norRR_inj)
  10.303 -        apply (auto intro: order_less_le [THEN iffD2]
  10.304 -           simp add: noX_is_RRset)
  10.305 -  apply (unfold noXRRset_def norRRset_def)
  10.306 -  apply (rule finite_imageI)
  10.307 -  apply (rule Bnor_fin)
  10.308 -  done
  10.309 -
  10.310 -lemma Bnor_prime:
  10.311 -  "\<lbrakk> zprime p; a < p \<rbrakk> \<Longrightarrow> card (BnorRset a p) = nat a"
  10.312 -  apply (induct a p rule: BnorRset.induct)
  10.313 -  apply (subst BnorRset.simps)
  10.314 -  apply (unfold Let_def, auto simp add:zless_zprime_imp_zrelprime)
  10.315 -  apply (subgoal_tac "finite (BnorRset (a - 1) m)")
  10.316 -   apply (subgoal_tac "a ~: BnorRset (a - 1) m")
  10.317 -    apply (auto simp add: card_insert_disjoint Suc_nat_eq_nat_zadd1)
  10.318 -   apply (frule Bnor_mem_zle, arith)
  10.319 -  apply (frule Bnor_fin)
  10.320 -  done
  10.321 -
  10.322 -lemma phi_prime: "zprime p ==> phi p = nat (p - 1)"
  10.323 -  apply (unfold phi_def norRRset_def)
  10.324 -  apply (rule Bnor_prime, auto)
  10.325 -  done
  10.326 -
  10.327 -theorem Little_Fermat:
  10.328 -    "zprime p ==> \<not> p dvd x ==> [x^(nat (p - 1)) = 1] (mod p)"
  10.329 -  apply (subst phi_prime [symmetric])
  10.330 -   apply (rule_tac [2] Euler_Fermat)
  10.331 -    apply (erule_tac [3] zprime_imp_zrelprime)
  10.332 -    apply (unfold zprime_def, auto)
  10.333 -  done
  10.334 -
  10.335 -end
    11.1 --- a/src/HOL/Old_Number_Theory/EvenOdd.thy	Tue Oct 18 07:04:08 2016 +0200
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,261 +0,0 @@
    11.4 -(*  Title:      HOL/Old_Number_Theory/EvenOdd.thy
    11.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
    11.6 -*)
    11.7 -
    11.8 -section \<open>Parity: Even and Odd Integers\<close>
    11.9 -
   11.10 -theory EvenOdd
   11.11 -imports Int2
   11.12 -begin
   11.13 -
   11.14 -definition zOdd :: "int set"
   11.15 -  where "zOdd = {x. \<exists>k. x = 2 * k + 1}"
   11.16 -
   11.17 -definition zEven :: "int set"
   11.18 -  where "zEven = {x. \<exists>k. x = 2 * k}"
   11.19 -
   11.20 -lemma in_zEven_zOdd_iff:
   11.21 -  fixes k :: int
   11.22 -  shows "k \<in> zEven \<longleftrightarrow> even k"
   11.23 -    and "k \<in> zOdd \<longleftrightarrow> odd k"
   11.24 -  by (auto simp add: zEven_def zOdd_def elim: evenE oddE)
   11.25 -
   11.26 -
   11.27 -subsection \<open>Some useful properties about even and odd\<close>
   11.28 -
   11.29 -lemma zOddI [intro?]: "x = 2 * k + 1 \<Longrightarrow> x \<in> zOdd"
   11.30 -  and zOddE [elim?]: "x \<in> zOdd \<Longrightarrow> (!!k. x = 2 * k + 1 \<Longrightarrow> C) \<Longrightarrow> C"
   11.31 -  by (auto simp add: zOdd_def)
   11.32 -
   11.33 -lemma zEvenI [intro?]: "x = 2 * k \<Longrightarrow> x \<in> zEven"
   11.34 -  and zEvenE [elim?]: "x \<in> zEven \<Longrightarrow> (!!k. x = 2 * k \<Longrightarrow> C) \<Longrightarrow> C"
   11.35 -  by (auto simp add: zEven_def)
   11.36 -
   11.37 -lemma one_not_even: "~(1 \<in> zEven)"
   11.38 -proof
   11.39 -  assume "1 \<in> zEven"
   11.40 -  then obtain k :: int where "1 = 2 * k" ..
   11.41 -  then show False by arith
   11.42 -qed
   11.43 -
   11.44 -lemma even_odd_conj: "~(x \<in> zOdd & x \<in> zEven)"
   11.45 -proof -
   11.46 -  {
   11.47 -    fix a b
   11.48 -    assume "2 * (a::int) = 2 * (b::int) + 1"
   11.49 -    then have "2 * (a::int) - 2 * (b :: int) = 1"
   11.50 -      by arith
   11.51 -    then have "2 * (a - b) = 1"
   11.52 -      by (auto simp add: left_diff_distrib)
   11.53 -    moreover have "(2 * (a - b)):zEven"
   11.54 -      by (auto simp only: zEven_def)
   11.55 -    ultimately have False
   11.56 -      by (auto simp add: one_not_even)
   11.57 -  }
   11.58 -  then show ?thesis
   11.59 -    by (auto simp add: zOdd_def zEven_def)
   11.60 -qed
   11.61 -
   11.62 -lemma even_odd_disj: "(x \<in> zOdd | x \<in> zEven)"
   11.63 -  by (simp add: zOdd_def zEven_def) arith
   11.64 -
   11.65 -lemma not_odd_impl_even: "~(x \<in> zOdd) ==> x \<in> zEven"
   11.66 -  using even_odd_disj by auto
   11.67 -
   11.68 -lemma odd_mult_odd_prop: "(x*y):zOdd ==> x \<in> zOdd"
   11.69 -proof (rule classical)
   11.70 -  assume "\<not> ?thesis"
   11.71 -  then have "x \<in> zEven" by (rule not_odd_impl_even)
   11.72 -  then obtain a where a: "x = 2 * a" ..
   11.73 -  assume "x * y : zOdd"
   11.74 -  then obtain b where "x * y = 2 * b + 1" ..
   11.75 -  with a have "2 * a * y = 2 * b + 1" by simp
   11.76 -  then have "2 * a * y - 2 * b = 1"
   11.77 -    by arith
   11.78 -  then have "2 * (a * y - b) = 1"
   11.79 -    by (auto simp add: left_diff_distrib)
   11.80 -  moreover have "(2 * (a * y - b)):zEven"
   11.81 -    by (auto simp only: zEven_def)
   11.82 -  ultimately have False
   11.83 -    by (auto simp add: one_not_even)
   11.84 -  then show ?thesis ..
   11.85 -qed
   11.86 -
   11.87 -lemma odd_minus_one_even: "x \<in> zOdd ==> (x - 1):zEven"
   11.88 -  by (auto simp add: zOdd_def zEven_def)
   11.89 -
   11.90 -lemma even_div_2_prop1: "x \<in> zEven ==> (x mod 2) = 0"
   11.91 -  by (auto simp add: zEven_def)
   11.92 -
   11.93 -lemma even_div_2_prop2: "x \<in> zEven ==> (2 * (x div 2)) = x"
   11.94 -  by (auto simp add: zEven_def)
   11.95 -
   11.96 -lemma even_plus_even: "[| x \<in> zEven; y \<in> zEven |] ==> x + y \<in> zEven"
   11.97 -  apply (auto simp add: zEven_def)
   11.98 -  apply (auto simp only: distrib_left [symmetric])
   11.99 -  done
  11.100 -
  11.101 -lemma even_times_either: "x \<in> zEven ==> x * y \<in> zEven"
  11.102 -  by (auto simp add: zEven_def)
  11.103 -
  11.104 -lemma even_minus_even: "[| x \<in> zEven; y \<in> zEven |] ==> x - y \<in> zEven"
  11.105 -  apply (auto simp add: zEven_def)
  11.106 -  apply (auto simp only: right_diff_distrib [symmetric])
  11.107 -  done
  11.108 -
  11.109 -lemma odd_minus_odd: "[| x \<in> zOdd; y \<in> zOdd |] ==> x - y \<in> zEven"
  11.110 -  apply (auto simp add: zOdd_def zEven_def)
  11.111 -  apply (auto simp only: right_diff_distrib [symmetric])
  11.112 -  done
  11.113 -
  11.114 -lemma even_minus_odd: "[| x \<in> zEven; y \<in> zOdd |] ==> x - y \<in> zOdd"
  11.115 -  apply (auto simp add: zOdd_def zEven_def)
  11.116 -  apply (rule_tac x = "k - ka - 1" in exI)
  11.117 -  apply auto
  11.118 -  done
  11.119 -
  11.120 -lemma odd_minus_even: "[| x \<in> zOdd; y \<in> zEven |] ==> x - y \<in> zOdd"
  11.121 -  apply (auto simp add: zOdd_def zEven_def)
  11.122 -  apply (auto simp only: right_diff_distrib [symmetric])
  11.123 -  done
  11.124 -
  11.125 -lemma odd_times_odd: "[| x \<in> zOdd;  y \<in> zOdd |] ==> x * y \<in> zOdd"
  11.126 -  apply (auto simp add: zOdd_def distrib_right distrib_left)
  11.127 -  apply (rule_tac x = "2 * ka * k + ka + k" in exI)
  11.128 -  apply (auto simp add: distrib_right)
  11.129 -  done
  11.130 -
  11.131 -lemma odd_iff_not_even: "(x \<in> zOdd) = (~ (x \<in> zEven))"
  11.132 -  using even_odd_conj even_odd_disj by auto
  11.133 -
  11.134 -lemma even_product: "x * y \<in> zEven ==> x \<in> zEven | y \<in> zEven"
  11.135 -  using odd_iff_not_even odd_times_odd by auto
  11.136 -
  11.137 -lemma even_diff: "x - y \<in> zEven = ((x \<in> zEven) = (y \<in> zEven))"
  11.138 -proof
  11.139 -  assume xy: "x - y \<in> zEven"
  11.140 -  {
  11.141 -    assume x: "x \<in> zEven"
  11.142 -    have "y \<in> zEven"
  11.143 -    proof (rule classical)
  11.144 -      assume "\<not> ?thesis"
  11.145 -      then have "y \<in> zOdd"
  11.146 -        by (simp add: odd_iff_not_even)
  11.147 -      with x have "x - y \<in> zOdd"
  11.148 -        by (simp add: even_minus_odd)
  11.149 -      with xy have False
  11.150 -        by (auto simp add: odd_iff_not_even)
  11.151 -      then show ?thesis ..
  11.152 -    qed
  11.153 -  } moreover {
  11.154 -    assume y: "y \<in> zEven"
  11.155 -    have "x \<in> zEven"
  11.156 -    proof (rule classical)
  11.157 -      assume "\<not> ?thesis"
  11.158 -      then have "x \<in> zOdd"
  11.159 -        by (auto simp add: odd_iff_not_even)
  11.160 -      with y have "x - y \<in> zOdd"
  11.161 -        by (simp add: odd_minus_even)
  11.162 -      with xy have False
  11.163 -        by (auto simp add: odd_iff_not_even)
  11.164 -      then show ?thesis ..
  11.165 -    qed
  11.166 -  }
  11.167 -  ultimately show "(x \<in> zEven) = (y \<in> zEven)"
  11.168 -    by (auto simp add: odd_iff_not_even even_minus_even odd_minus_odd
  11.169 -      even_minus_odd odd_minus_even)
  11.170 -next
  11.171 -  assume "(x \<in> zEven) = (y \<in> zEven)"
  11.172 -  then show "x - y \<in> zEven"
  11.173 -    by (auto simp add: odd_iff_not_even even_minus_even odd_minus_odd
  11.174 -      even_minus_odd odd_minus_even)
  11.175 -qed
  11.176 -
  11.177 -lemma neg_one_even_power: "[| x \<in> zEven; 0 \<le> x |] ==> (-1::int)^(nat x) = 1"
  11.178 -proof -
  11.179 -  assume "x \<in> zEven" and "0 \<le> x"
  11.180 -  from \<open>x \<in> zEven\<close> obtain a where "x = 2 * a" ..
  11.181 -  with \<open>0 \<le> x\<close> have "0 \<le> a" by simp
  11.182 -  from \<open>0 \<le> x\<close> and \<open>x = 2 * a\<close> have "nat x = nat (2 * a)"
  11.183 -    by simp
  11.184 -  also from \<open>x = 2 * a\<close> have "nat (2 * a) = 2 * nat a"
  11.185 -    by (simp add: nat_mult_distrib)
  11.186 -  finally have "(-1::int)^nat x = (-1)^(2 * nat a)"
  11.187 -    by simp
  11.188 -  also have "... = (-1::int)\<^sup>2 ^ nat a"
  11.189 -    by (simp add: power_mult)
  11.190 -  also have "(-1::int)\<^sup>2 = 1"
  11.191 -    by simp
  11.192 -  finally show ?thesis
  11.193 -    by simp
  11.194 -qed
  11.195 -
  11.196 -lemma neg_one_odd_power: "[| x \<in> zOdd; 0 \<le> x |] ==> (-1::int)^(nat x) = -1"
  11.197 -proof -
  11.198 -  assume "x \<in> zOdd" and "0 \<le> x"
  11.199 -  from \<open>x \<in> zOdd\<close> obtain a where "x = 2 * a + 1" ..
  11.200 -  with \<open>0 \<le> x\<close> have a: "0 \<le> a" by simp
  11.201 -  with \<open>0 \<le> x\<close> and \<open>x = 2 * a + 1\<close> have "nat x = nat (2 * a + 1)"
  11.202 -    by simp
  11.203 -  also from a have "nat (2 * a + 1) = 2 * nat a + 1"
  11.204 -    by (auto simp add: nat_mult_distrib nat_add_distrib)
  11.205 -  finally have "(-1::int) ^ nat x = (-1)^(2 * nat a + 1)"
  11.206 -    by simp
  11.207 -  also have "... = ((-1::int)\<^sup>2) ^ nat a * (-1)^1"
  11.208 -    by (auto simp add: power_mult power_add)
  11.209 -  also have "(-1::int)\<^sup>2 = 1"
  11.210 -    by simp
  11.211 -  finally show ?thesis
  11.212 -    by simp
  11.213 -qed
  11.214 -
  11.215 -lemma neg_one_power_parity: "[| 0 \<le> x; 0 \<le> y; (x \<in> zEven) = (y \<in> zEven) |] ==>
  11.216 -    (-1::int)^(nat x) = (-1::int)^(nat y)"
  11.217 -  using even_odd_disj [of x] even_odd_disj [of y]
  11.218 -  by (auto simp add: neg_one_even_power neg_one_odd_power)
  11.219 -
  11.220 -
  11.221 -lemma one_not_neg_one_mod_m: "2 < m ==> ~([1 = -1] (mod m))"
  11.222 -  by (auto simp add: zcong_def zdvd_not_zless)
  11.223 -
  11.224 -lemma even_div_2_l: "[| y \<in> zEven; x < y |] ==> x div 2 < y div 2"
  11.225 -proof -
  11.226 -  assume "y \<in> zEven" and "x < y"
  11.227 -  from \<open>y \<in> zEven\<close> obtain k where k: "y = 2 * k" ..
  11.228 -  with \<open>x < y\<close> have "x < 2 * k" by simp
  11.229 -  then have "x div 2 < k" by (auto simp add: div_prop1)
  11.230 -  also have "k = (2 * k) div 2" by simp
  11.231 -  finally have "x div 2 < 2 * k div 2" by simp
  11.232 -  with k show ?thesis by simp
  11.233 -qed
  11.234 -
  11.235 -lemma even_sum_div_2: "[| x \<in> zEven; y \<in> zEven |] ==> (x + y) div 2 = x div 2 + y div 2"
  11.236 -  by (auto simp add: zEven_def)
  11.237 -
  11.238 -lemma even_prod_div_2: "[| x \<in> zEven |] ==> (x * y) div 2 = (x div 2) * y"
  11.239 -  by (auto simp add: zEven_def)
  11.240 -
  11.241 -(* An odd prime is greater than 2 *)
  11.242 -
  11.243 -lemma zprime_zOdd_eq_grt_2: "zprime p ==> (p \<in> zOdd) = (2 < p)"
  11.244 -  apply (auto simp add: zOdd_def zprime_def)
  11.245 -  apply (drule_tac x = 2 in allE)
  11.246 -  using odd_iff_not_even [of p]
  11.247 -  apply (auto simp add: zOdd_def zEven_def)
  11.248 -  done
  11.249 -
  11.250 -(* Powers of -1 and parity *)
  11.251 -
  11.252 -lemma neg_one_special: "finite A ==>
  11.253 -  ((- 1) ^ card A) * ((- 1) ^ card A) = (1 :: int)"
  11.254 -  unfolding power_add [symmetric] by simp
  11.255 -
  11.256 -lemma neg_one_power: "(-1::int)^n = 1 | (-1::int)^n = -1"
  11.257 -  by (induct n) auto
  11.258 -
  11.259 -lemma neg_one_power_eq_mod_m: "[| 2 < m; [(-1::int)^j = (-1::int)^k] (mod m) |]
  11.260 -    ==> ((-1::int)^j = (-1::int)^k)"
  11.261 -  using neg_one_power [of j] and ListMem.insert neg_one_power [of k]
  11.262 -  by (auto simp add: one_not_neg_one_mod_m zcong_sym)
  11.263 -
  11.264 -end
    12.1 --- a/src/HOL/Old_Number_Theory/Factorization.thy	Tue Oct 18 07:04:08 2016 +0200
    12.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.3 @@ -1,339 +0,0 @@
    12.4 -(*  Title:      HOL/Old_Number_Theory/Factorization.thy
    12.5 -    Author:     Thomas Marthedal Rasmussen
    12.6 -    Copyright   2000  University of Cambridge
    12.7 -*)
    12.8 -
    12.9 -section \<open>Fundamental Theorem of Arithmetic (unique factorization into primes)\<close>
   12.10 -
   12.11 -theory Factorization
   12.12 -imports Primes "~~/src/HOL/Library/Permutation"
   12.13 -begin
   12.14 -
   12.15 -
   12.16 -subsection \<open>Definitions\<close>
   12.17 -
   12.18 -definition primel :: "nat list => bool"
   12.19 -  where "primel xs = (\<forall>p \<in> set xs. prime p)"
   12.20 -
   12.21 -primrec nondec :: "nat list => bool"
   12.22 -where
   12.23 -  "nondec [] = True"
   12.24 -| "nondec (x # xs) = (case xs of [] => True | y # ys => x \<le> y \<and> nondec xs)"
   12.25 -
   12.26 -primrec prod :: "nat list => nat"
   12.27 -where
   12.28 -  "prod [] = Suc 0"
   12.29 -| "prod (x # xs) = x * prod xs"
   12.30 -
   12.31 -primrec oinsert :: "nat => nat list => nat list"
   12.32 -where
   12.33 -  "oinsert x [] = [x]"
   12.34 -| "oinsert x (y # ys) = (if x \<le> y then x # y # ys else y # oinsert x ys)"
   12.35 -
   12.36 -primrec sort :: "nat list => nat list"
   12.37 -where
   12.38 -  "sort [] = []"
   12.39 -| "sort (x # xs) = oinsert x (sort xs)"
   12.40 -
   12.41 -
   12.42 -subsection \<open>Arithmetic\<close>
   12.43 -
   12.44 -lemma one_less_m: "(m::nat) \<noteq> m * k ==> m \<noteq> Suc 0 ==> Suc 0 < m"
   12.45 -  apply (cases m)
   12.46 -   apply auto
   12.47 -  done
   12.48 -
   12.49 -lemma one_less_k: "(m::nat) \<noteq> m * k ==> Suc 0 < m * k ==> Suc 0 < k"
   12.50 -  apply (cases k)
   12.51 -   apply auto
   12.52 -  done
   12.53 -
   12.54 -lemma mult_left_cancel: "(0::nat) < k ==> k * n = k * m ==> n = m"
   12.55 -  apply auto
   12.56 -  done
   12.57 -
   12.58 -lemma mn_eq_m_one: "(0::nat) < m ==> m * n = m ==> n = Suc 0"
   12.59 -  apply (cases n)
   12.60 -   apply auto
   12.61 -  done
   12.62 -
   12.63 -lemma prod_mn_less_k:
   12.64 -    "(0::nat) < n ==> 0 < k ==> Suc 0 < m ==> m * n = k ==> n < k"
   12.65 -  apply (induct m)
   12.66 -   apply auto
   12.67 -  done
   12.68 -
   12.69 -
   12.70 -subsection \<open>Prime list and product\<close>
   12.71 -
   12.72 -lemma prod_append: "prod (xs @ ys) = prod xs * prod ys"
   12.73 -  apply (induct xs)
   12.74 -   apply (simp_all add: mult.assoc)
   12.75 -  done
   12.76 -
   12.77 -lemma prod_xy_prod:
   12.78 -    "prod (x # xs) = prod (y # ys) ==> x * prod xs = y * prod ys"
   12.79 -  apply auto
   12.80 -  done
   12.81 -
   12.82 -lemma primel_append: "primel (xs @ ys) = (primel xs \<and> primel ys)"
   12.83 -  apply (unfold primel_def)
   12.84 -  apply auto
   12.85 -  done
   12.86 -
   12.87 -lemma prime_primel: "prime n ==> primel [n] \<and> prod [n] = n"
   12.88 -  apply (unfold primel_def)
   12.89 -  apply auto
   12.90 -  done
   12.91 -
   12.92 -lemma prime_nd_one: "prime p ==> \<not> p dvd Suc 0"
   12.93 -  apply (unfold prime_def dvd_def)
   12.94 -  apply auto
   12.95 -  done
   12.96 -
   12.97 -lemma hd_dvd_prod: "prod (x # xs) = prod ys ==> x dvd (prod ys)" 
   12.98 -  by (metis dvd_mult_left dvd_refl prod.simps(2))
   12.99 -
  12.100 -lemma primel_tl: "primel (x # xs) ==> primel xs"
  12.101 -  apply (unfold primel_def)
  12.102 -  apply auto
  12.103 -  done
  12.104 -
  12.105 -lemma primel_hd_tl: "(primel (x # xs)) = (prime x \<and> primel xs)"
  12.106 -  apply (unfold primel_def)
  12.107 -  apply auto
  12.108 -  done
  12.109 -
  12.110 -lemma primes_eq: "prime p ==> prime q ==> p dvd q ==> p = q"
  12.111 -  apply (unfold prime_def)
  12.112 -  apply auto
  12.113 -  done
  12.114 -
  12.115 -lemma primel_one_empty: "primel xs ==> prod xs = Suc 0 ==> xs = []"
  12.116 -  apply (cases xs)
  12.117 -   apply (simp_all add: primel_def prime_def)
  12.118 -  done
  12.119 -
  12.120 -lemma prime_g_one: "prime p ==> Suc 0 < p"
  12.121 -  apply (unfold prime_def)
  12.122 -  apply auto
  12.123 -  done
  12.124 -
  12.125 -lemma prime_g_zero: "prime p ==> 0 < p"
  12.126 -  apply (unfold prime_def)
  12.127 -  apply auto
  12.128 -  done
  12.129 -
  12.130 -lemma primel_nempty_g_one:
  12.131 -    "primel xs \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> Suc 0 < prod xs"
  12.132 -  apply (induct xs)
  12.133 -   apply simp
  12.134 -  apply (fastforce simp: primel_def prime_def elim: one_less_mult)
  12.135 -  done
  12.136 -
  12.137 -lemma primel_prod_gz: "primel xs ==> 0 < prod xs"
  12.138 -  apply (induct xs)
  12.139 -   apply (auto simp: primel_def prime_def)
  12.140 -  done
  12.141 -
  12.142 -
  12.143 -subsection \<open>Sorting\<close>
  12.144 -
  12.145 -lemma nondec_oinsert: "nondec xs \<Longrightarrow> nondec (oinsert x xs)"
  12.146 -  apply (induct xs)
  12.147 -   apply simp
  12.148 -   apply (case_tac xs)
  12.149 -    apply (simp_all cong del: list.case_cong_weak)
  12.150 -  done
  12.151 -
  12.152 -lemma nondec_sort: "nondec (sort xs)"
  12.153 -  apply (induct xs)
  12.154 -   apply simp_all
  12.155 -  apply (erule nondec_oinsert)
  12.156 -  done
  12.157 -
  12.158 -lemma x_less_y_oinsert: "x \<le> y ==> l = y # ys ==> x # l = oinsert x l"
  12.159 -  apply simp_all
  12.160 -  done
  12.161 -
  12.162 -lemma nondec_sort_eq [rule_format]: "nondec xs \<longrightarrow> xs = sort xs"
  12.163 -  apply (induct xs)
  12.164 -   apply safe
  12.165 -    apply simp_all
  12.166 -   apply (case_tac xs)
  12.167 -    apply simp_all
  12.168 -  apply (case_tac xs)
  12.169 -   apply simp
  12.170 -  apply (rule_tac y = aa and ys = list in x_less_y_oinsert)
  12.171 -   apply simp_all
  12.172 -  done
  12.173 -
  12.174 -lemma oinsert_x_y: "oinsert x (oinsert y l) = oinsert y (oinsert x l)"
  12.175 -  apply (induct l)
  12.176 -  apply auto
  12.177 -  done
  12.178 -
  12.179 -
  12.180 -subsection \<open>Permutation\<close>
  12.181 -
  12.182 -lemma perm_primel [rule_format]: "xs <~~> ys ==> primel xs --> primel ys"
  12.183 -  apply (unfold primel_def)
  12.184 -  apply (induct set: perm)
  12.185 -     apply simp
  12.186 -    apply simp
  12.187 -   apply (simp (no_asm))
  12.188 -   apply blast
  12.189 -  apply blast
  12.190 -  done
  12.191 -
  12.192 -lemma perm_prod: "xs <~~> ys ==> prod xs = prod ys"
  12.193 -  apply (induct set: perm)
  12.194 -     apply (simp_all add: ac_simps)
  12.195 -  done
  12.196 -
  12.197 -lemma perm_subst_oinsert: "xs <~~> ys ==> oinsert a xs <~~> oinsert a ys"
  12.198 -  apply (induct set: perm)
  12.199 -     apply auto
  12.200 -  done
  12.201 -
  12.202 -lemma perm_oinsert: "x # xs <~~> oinsert x xs"
  12.203 -  apply (induct xs)
  12.204 -   apply auto
  12.205 -  done
  12.206 -
  12.207 -lemma perm_sort: "xs <~~> sort xs"
  12.208 -  apply (induct xs)
  12.209 -  apply (auto intro: perm_oinsert elim: perm_subst_oinsert)
  12.210 -  done
  12.211 -
  12.212 -lemma perm_sort_eq: "xs <~~> ys ==> sort xs = sort ys"
  12.213 -  apply (induct set: perm)
  12.214 -     apply (simp_all add: oinsert_x_y)
  12.215 -  done
  12.216 -
  12.217 -
  12.218 -subsection \<open>Existence\<close>
  12.219 -
  12.220 -lemma ex_nondec_lemma:
  12.221 -    "primel xs ==> \<exists>ys. primel ys \<and> nondec ys \<and> prod ys = prod xs"
  12.222 -  apply (blast intro: nondec_sort perm_prod perm_primel perm_sort perm_sym)
  12.223 -  done
  12.224 -
  12.225 -lemma not_prime_ex_mk:
  12.226 -  "Suc 0 < n \<and> \<not> prime n \<Longrightarrow>
  12.227 -    \<exists>m k. Suc 0 < m \<and> Suc 0 < k \<and> m < n \<and> k < n \<and> n = m * k"
  12.228 -  apply (unfold prime_def dvd_def)
  12.229 -  apply (auto intro: n_less_m_mult_n n_less_n_mult_m one_less_m one_less_k)
  12.230 -  using n_less_m_mult_n n_less_n_mult_m one_less_m one_less_k
  12.231 -  apply (metis Suc_lessD Suc_lessI mult.commute)
  12.232 -  done
  12.233 -
  12.234 -lemma split_primel:
  12.235 -  "primel xs \<Longrightarrow> primel ys \<Longrightarrow> \<exists>l. primel l \<and> prod l = prod xs * prod ys"
  12.236 -  apply (rule exI)
  12.237 -  apply safe
  12.238 -   apply (rule_tac [2] prod_append)
  12.239 -  apply (simp add: primel_append)
  12.240 -  done
  12.241 -
  12.242 -lemma factor_exists [rule_format]: "Suc 0 < n --> (\<exists>l. primel l \<and> prod l = n)"
  12.243 -  apply (induct n rule: nat_less_induct)
  12.244 -  apply (rule impI)
  12.245 -  apply (case_tac "prime n")
  12.246 -   apply (rule exI)
  12.247 -   apply (erule prime_primel)
  12.248 -  apply (cut_tac n = n in not_prime_ex_mk)
  12.249 -   apply (auto intro!: split_primel)
  12.250 -  done
  12.251 -
  12.252 -lemma nondec_factor_exists: "Suc 0 < n ==> \<exists>l. primel l \<and> nondec l \<and> prod l = n"
  12.253 -  apply (erule factor_exists [THEN exE])
  12.254 -  apply (blast intro!: ex_nondec_lemma)
  12.255 -  done
  12.256 -
  12.257 -
  12.258 -subsection \<open>Uniqueness\<close>
  12.259 -
  12.260 -lemma prime_dvd_mult_list [rule_format]:
  12.261 -    "prime p ==> p dvd (prod xs) --> (\<exists>m. m:set xs \<and> p dvd m)"
  12.262 -  apply (induct xs)
  12.263 -   apply (force simp add: prime_def)
  12.264 -   apply (force dest: prime_dvd_mult)
  12.265 -  done
  12.266 -
  12.267 -lemma hd_xs_dvd_prod:
  12.268 -  "primel (x # xs) ==> primel ys ==> prod (x # xs) = prod ys
  12.269 -    ==> \<exists>m. m \<in> set ys \<and> x dvd m"
  12.270 -  apply (rule prime_dvd_mult_list)
  12.271 -   apply (simp add: primel_hd_tl)
  12.272 -  apply (erule hd_dvd_prod)
  12.273 -  done
  12.274 -
  12.275 -lemma prime_dvd_eq: "primel (x # xs) ==> primel ys ==> m \<in> set ys ==> x dvd m ==> x = m"
  12.276 -  apply (rule primes_eq)
  12.277 -    apply (auto simp add: primel_def primel_hd_tl)
  12.278 -  done
  12.279 -
  12.280 -lemma hd_xs_eq_prod:
  12.281 -  "primel (x # xs) ==>
  12.282 -    primel ys ==> prod (x # xs) = prod ys ==> x \<in> set ys"
  12.283 -  apply (frule hd_xs_dvd_prod)
  12.284 -    apply auto
  12.285 -  apply (drule prime_dvd_eq)
  12.286 -     apply auto
  12.287 -  done
  12.288 -
  12.289 -lemma perm_primel_ex:
  12.290 -  "primel (x # xs) ==>
  12.291 -    primel ys ==> prod (x # xs) = prod ys ==> \<exists>l. ys <~~> (x # l)"
  12.292 -  apply (rule exI)
  12.293 -  apply (rule perm_remove)
  12.294 -  apply (erule hd_xs_eq_prod)
  12.295 -   apply simp_all
  12.296 -  done
  12.297 -
  12.298 -lemma primel_prod_less:
  12.299 -  "primel (x # xs) ==>
  12.300 -    primel ys ==> prod (x # xs) = prod ys ==> prod xs < prod ys"
  12.301 -  by (metis less_asym linorder_neqE_nat mult_less_cancel2 nat_0_less_mult_iff
  12.302 -    nat_less_le nat_mult_1 prime_def primel_hd_tl primel_prod_gz prod.simps(2))
  12.303 -
  12.304 -lemma prod_one_empty:
  12.305 -    "primel xs ==> p * prod xs = p ==> prime p ==> xs = []"
  12.306 -  apply (auto intro: primel_one_empty simp add: prime_def)
  12.307 -  done
  12.308 -
  12.309 -lemma uniq_ex_aux:
  12.310 -  "\<forall>m. m < prod ys --> (\<forall>xs ys. primel xs \<and> primel ys \<and>
  12.311 -      prod xs = prod ys \<and> prod xs = m --> xs <~~> ys) ==>
  12.312 -    primel list ==> primel x ==> prod list = prod x ==> prod x < prod ys
  12.313 -    ==> x <~~> list"
  12.314 -  apply simp
  12.315 -  done
  12.316 -
  12.317 -lemma factor_unique [rule_format]:
  12.318 -  "\<forall>xs ys. primel xs \<and> primel ys \<and> prod xs = prod ys \<and> prod xs = n
  12.319 -    --> xs <~~> ys"
  12.320 -  apply (induct n rule: nat_less_induct)
  12.321 -  apply safe
  12.322 -  apply (case_tac xs)
  12.323 -   apply (force intro: primel_one_empty)
  12.324 -  apply (rule perm_primel_ex [THEN exE])
  12.325 -     apply simp_all
  12.326 -  apply (rule perm.trans [THEN perm_sym])
  12.327 -  apply assumption
  12.328 -  apply (rule perm.Cons)
  12.329 -  apply (case_tac "x = []")
  12.330 -   apply (metis perm_prod perm_refl prime_primel primel_hd_tl primel_tl prod_one_empty)
  12.331 -  apply (metis nat_0_less_mult_iff nat_mult_eq_cancel1 perm_primel perm_prod primel_prod_gz primel_prod_less primel_tl prod.simps(2))
  12.332 -  done
  12.333 -
  12.334 -lemma perm_nondec_unique:
  12.335 -    "xs <~~> ys ==> nondec xs ==> nondec ys ==> xs = ys"
  12.336 -  by (metis nondec_sort_eq perm_sort_eq)
  12.337 -
  12.338 -theorem unique_prime_factorization [rule_format]:
  12.339 -    "\<forall>n. Suc 0 < n --> (\<exists>!l. primel l \<and> nondec l \<and> prod l = n)"
  12.340 -  by (metis factor_unique nondec_factor_exists perm_nondec_unique)
  12.341 -
  12.342 -end
    13.1 --- a/src/HOL/Old_Number_Theory/Fib.thy	Tue Oct 18 07:04:08 2016 +0200
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,148 +0,0 @@
    13.4 -(*  Title:      HOL/Old_Number_Theory/Fib.thy
    13.5 -    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
    13.6 -    Copyright   1997  University of Cambridge
    13.7 -*)
    13.8 -
    13.9 -section \<open>The Fibonacci function\<close>
   13.10 -
   13.11 -theory Fib
   13.12 -imports Primes
   13.13 -begin
   13.14 -
   13.15 -text \<open>
   13.16 -  Fibonacci numbers: proofs of laws taken from:
   13.17 -  R. L. Graham, D. E. Knuth, O. Patashnik.  Concrete Mathematics.
   13.18 -  (Addison-Wesley, 1989)
   13.19 -
   13.20 -  \bigskip
   13.21 -\<close>
   13.22 -
   13.23 -fun fib :: "nat \<Rightarrow> nat"
   13.24 -where
   13.25 -  "fib 0 = 0"
   13.26 -| "fib (Suc 0) = 1"
   13.27 -| fib_2: "fib (Suc (Suc n)) = fib n + fib (Suc n)"
   13.28 -
   13.29 -text \<open>
   13.30 -  \medskip The difficulty in these proofs is to ensure that the
   13.31 -  induction hypotheses are applied before the definition of @{term
   13.32 -  fib}.  Towards this end, the @{term fib} equations are not declared
   13.33 -  to the Simplifier and are applied very selectively at first.
   13.34 -\<close>
   13.35 -
   13.36 -text\<open>We disable \<open>fib.fib_2fib_2\<close> for simplification ...\<close>
   13.37 -declare fib_2 [simp del]
   13.38 -
   13.39 -text\<open>...then prove a version that has a more restrictive pattern.\<close>
   13.40 -lemma fib_Suc3: "fib (Suc (Suc (Suc n))) = fib (Suc n) + fib (Suc (Suc n))"
   13.41 -  by (rule fib_2)
   13.42 -
   13.43 -text \<open>\medskip Concrete Mathematics, page 280\<close>
   13.44 -
   13.45 -lemma fib_add: "fib (Suc (n + k)) = fib (Suc k) * fib (Suc n) + fib k * fib n"
   13.46 -proof (induct n rule: fib.induct)
   13.47 -  case 1 show ?case by simp
   13.48 -next
   13.49 -  case 2 show ?case  by (simp add: fib_2)
   13.50 -next
   13.51 -  case 3 thus ?case by (simp add: fib_2 add_mult_distrib2)
   13.52 -qed
   13.53 -
   13.54 -lemma fib_Suc_neq_0: "fib (Suc n) \<noteq> 0"
   13.55 -  apply (induct n rule: fib.induct)
   13.56 -    apply (simp_all add: fib_2)
   13.57 -  done
   13.58 -
   13.59 -lemma fib_Suc_gr_0: "0 < fib (Suc n)"
   13.60 -  by (insert fib_Suc_neq_0 [of n], simp)  
   13.61 -
   13.62 -lemma fib_gr_0: "0 < n ==> 0 < fib n"
   13.63 -  by (case_tac n, auto simp add: fib_Suc_gr_0) 
   13.64 -
   13.65 -
   13.66 -text \<open>
   13.67 -  \medskip Concrete Mathematics, page 278: Cassini's identity.  The proof is
   13.68 -  much easier using integers, not natural numbers!
   13.69 -\<close>
   13.70 -
   13.71 -lemma fib_Cassini_int:
   13.72 - "int (fib (Suc (Suc n)) * fib n) =
   13.73 -  (if n mod 2 = 0 then int (fib (Suc n) * fib (Suc n)) - 1
   13.74 -   else int (fib (Suc n) * fib (Suc n)) + 1)"
   13.75 -proof(induct n rule: fib.induct)
   13.76 -  case 1 thus ?case by (simp add: fib_2)
   13.77 -next
   13.78 -  case 2 thus ?case by (simp add: fib_2 mod_Suc)
   13.79 -next 
   13.80 -  case (3 x) 
   13.81 -  have "Suc 0 \<noteq> x mod 2 \<longrightarrow> x mod 2 = 0" by presburger
   13.82 -  with "3.hyps" show ?case by (simp add: fib.simps add_mult_distrib add_mult_distrib2)
   13.83 -qed
   13.84 -
   13.85 -text\<open>We now obtain a version for the natural numbers via the coercion 
   13.86 -   function @{term int}.\<close>
   13.87 -theorem fib_Cassini:
   13.88 - "fib (Suc (Suc n)) * fib n =
   13.89 -  (if n mod 2 = 0 then fib (Suc n) * fib (Suc n) - 1
   13.90 -   else fib (Suc n) * fib (Suc n) + 1)"
   13.91 -  apply (rule of_nat_eq_iff [where 'a = int, THEN iffD1]) 
   13.92 -  using fib_Cassini_int apply (auto simp add: Suc_leI fib_Suc_gr_0 of_nat_diff)
   13.93 -  done
   13.94 -
   13.95 -
   13.96 -text \<open>\medskip Toward Law 6.111 of Concrete Mathematics\<close>
   13.97 -
   13.98 -lemma gcd_fib_Suc_eq_1: "gcd (fib n) (fib (Suc n)) = Suc 0"
   13.99 -  apply (induct n rule: fib.induct)
  13.100 -    prefer 3
  13.101 -    apply (simp add: gcd_commute fib_Suc3)
  13.102 -   apply (simp_all add: fib_2)
  13.103 -  done
  13.104 -
  13.105 -lemma gcd_fib_add: "gcd (fib m) (fib (n + m)) = gcd (fib m) (fib n)"
  13.106 -  apply (simp add: gcd_commute [of "fib m"])
  13.107 -  apply (case_tac m)
  13.108 -   apply simp 
  13.109 -  apply (simp add: fib_add)
  13.110 -  apply (simp add: add.commute gcd_non_0 [OF fib_Suc_gr_0])
  13.111 -  apply (simp add: gcd_non_0 [OF fib_Suc_gr_0, symmetric])
  13.112 -  apply (simp add: gcd_fib_Suc_eq_1 gcd_mult_cancel)
  13.113 -  done
  13.114 -
  13.115 -lemma gcd_fib_diff: "m \<le> n ==> gcd (fib m) (fib (n - m)) = gcd (fib m) (fib n)"
  13.116 -  by (simp add: gcd_fib_add [symmetric, of _ "n-m"]) 
  13.117 -
  13.118 -lemma gcd_fib_mod: "0 < m ==> gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)"
  13.119 -proof (induct n rule: less_induct)
  13.120 -  case (less n)
  13.121 -  from less.prems have pos_m: "0 < m" .
  13.122 -  show "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)"
  13.123 -  proof (cases "m < n")
  13.124 -    case True note m_n = True
  13.125 -    then have m_n': "m \<le> n" by auto
  13.126 -    with pos_m have pos_n: "0 < n" by auto
  13.127 -    with pos_m m_n have diff: "n - m < n" by auto
  13.128 -    have "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib ((n - m) mod m))"
  13.129 -    by (simp add: mod_if [of n]) (insert m_n, auto)
  13.130 -    also have "\<dots> = gcd (fib m) (fib (n - m))" by (simp add: less.hyps diff pos_m)
  13.131 -    also have "\<dots> = gcd (fib m) (fib n)" by (simp add: gcd_fib_diff m_n')
  13.132 -    finally show "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" .
  13.133 -  next
  13.134 -    case False then show "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)"
  13.135 -    by (cases "m = n") auto
  13.136 -  qed
  13.137 -qed
  13.138 -
  13.139 -lemma fib_gcd: "fib (gcd m n) = gcd (fib m) (fib n)"  \<comment> \<open>Law 6.111\<close>
  13.140 -  apply (induct m n rule: gcd_induct)
  13.141 -  apply (simp_all add: gcd_non_0 gcd_commute gcd_fib_mod)
  13.142 -  done
  13.143 -
  13.144 -theorem fib_mult_eq_sum:
  13.145 -    "fib (Suc n) * fib n = (\<Sum>k \<in> {..n}. fib k * fib k)"
  13.146 -  apply (induct n rule: fib.induct)
  13.147 -    apply (auto simp add: atMost_Suc fib_2)
  13.148 -  apply (simp add: add_mult_distrib add_mult_distrib2)
  13.149 -  done
  13.150 -
  13.151 -end
    14.1 --- a/src/HOL/Old_Number_Theory/Finite2.thy	Tue Oct 18 07:04:08 2016 +0200
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,184 +0,0 @@
    14.4 -(*  Title:      HOL/Old_Number_Theory/Finite2.thy
    14.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
    14.6 -*)
    14.7 -
    14.8 -section \<open>Finite Sets and Finite Sums\<close>
    14.9 -
   14.10 -theory Finite2
   14.11 -imports IntFact "~~/src/HOL/Library/Infinite_Set"
   14.12 -begin
   14.13 -
   14.14 -text\<open>
   14.15 -  These are useful for combinatorial and number-theoretic counting
   14.16 -  arguments.
   14.17 -\<close>
   14.18 -
   14.19 -
   14.20 -subsection \<open>Useful properties of sums and products\<close>
   14.21 -
   14.22 -lemma sum_same_function_zcong:
   14.23 -  assumes a: "\<forall>x \<in> S. [f x = g x](mod m)"
   14.24 -  shows "[sum f S = sum g S] (mod m)"
   14.25 -proof cases
   14.26 -  assume "finite S"
   14.27 -  thus ?thesis using a by induct (simp_all add: zcong_zadd)
   14.28 -next
   14.29 -  assume "infinite S" thus ?thesis by simp
   14.30 -qed
   14.31 -
   14.32 -lemma prod_same_function_zcong:
   14.33 -  assumes a: "\<forall>x \<in> S. [f x = g x](mod m)"
   14.34 -  shows "[prod f S = prod g S] (mod m)"
   14.35 -proof cases
   14.36 -  assume "finite S"
   14.37 -  thus ?thesis using a by induct (simp_all add: zcong_zmult)
   14.38 -next
   14.39 -  assume "infinite S" thus ?thesis by simp
   14.40 -qed
   14.41 -
   14.42 -lemma sum_const: "finite X ==> sum (%x. (c :: int)) X = c * int(card X)"
   14.43 -by (simp add: of_nat_mult)
   14.44 -
   14.45 -lemma sum_const2: "finite X ==> int (sum (%x. (c :: nat)) X) =
   14.46 -    int(c) * int(card X)"
   14.47 -by (simp add: of_nat_mult)
   14.48 -
   14.49 -lemma sum_const_mult: "finite A ==> sum (%x. c * ((f x)::int)) A =
   14.50 -    c * sum f A"
   14.51 -  by (induct set: finite) (auto simp add: distrib_left)
   14.52 -
   14.53 -
   14.54 -subsection \<open>Cardinality of explicit finite sets\<close>
   14.55 -
   14.56 -lemma finite_surjI: "[| B \<subseteq> f ` A; finite A |] ==> finite B"
   14.57 -by (simp add: finite_subset)
   14.58 -
   14.59 -lemma bdd_nat_set_l_finite: "finite {y::nat . y < x}"
   14.60 -  by (rule bounded_nat_set_is_finite) blast
   14.61 -
   14.62 -lemma bdd_nat_set_le_finite: "finite {y::nat . y \<le> x}"
   14.63 -proof -
   14.64 -  have "{y::nat . y \<le> x} = {y::nat . y < Suc x}" by auto
   14.65 -  then show ?thesis by (auto simp add: bdd_nat_set_l_finite)
   14.66 -qed
   14.67 -
   14.68 -lemma  bdd_int_set_l_finite: "finite {x::int. 0 \<le> x & x < n}"
   14.69 -  apply (subgoal_tac " {(x :: int). 0 \<le> x & x < n} \<subseteq>
   14.70 -      int ` {(x :: nat). x < nat n}")
   14.71 -   apply (erule finite_surjI)
   14.72 -   apply (auto simp add: bdd_nat_set_l_finite image_def)
   14.73 -  apply (rule_tac x = "nat x" in exI, simp)
   14.74 -  done
   14.75 -
   14.76 -lemma bdd_int_set_le_finite: "finite {x::int. 0 \<le> x & x \<le> n}"
   14.77 -  apply (subgoal_tac "{x. 0 \<le> x & x \<le> n} = {x. 0 \<le> x & x < n + 1}")
   14.78 -   apply (erule ssubst)
   14.79 -   apply (rule bdd_int_set_l_finite)
   14.80 -  apply auto
   14.81 -  done
   14.82 -
   14.83 -lemma bdd_int_set_l_l_finite: "finite {x::int. 0 < x & x < n}"
   14.84 -proof -
   14.85 -  have "{x::int. 0 < x & x < n} \<subseteq> {x::int. 0 \<le> x & x < n}"
   14.86 -    by auto
   14.87 -  then show ?thesis by (auto simp add: bdd_int_set_l_finite finite_subset)
   14.88 -qed
   14.89 -
   14.90 -lemma bdd_int_set_l_le_finite: "finite {x::int. 0 < x & x \<le> n}"
   14.91 -proof -
   14.92 -  have "{x::int. 0 < x & x \<le> n} \<subseteq> {x::int. 0 \<le> x & x \<le> n}"
   14.93 -    by auto
   14.94 -  then show ?thesis by (auto simp add: bdd_int_set_le_finite finite_subset)
   14.95 -qed
   14.96 -
   14.97 -lemma card_bdd_nat_set_l: "card {y::nat . y < x} = x"
   14.98 -proof (induct x)
   14.99 -  case 0
  14.100 -  show "card {y::nat . y < 0} = 0" by simp
  14.101 -next
  14.102 -  case (Suc n)
  14.103 -  have "{y. y < Suc n} = insert n {y. y < n}"
  14.104 -    by auto
  14.105 -  then have "card {y. y < Suc n} = card (insert n {y. y < n})"
  14.106 -    by auto
  14.107 -  also have "... = Suc (card {y. y < n})"
  14.108 -    by (rule card_insert_disjoint) (auto simp add: bdd_nat_set_l_finite)
  14.109 -  finally show "card {y. y < Suc n} = Suc n"
  14.110 -    using \<open>card {y. y < n} = n\<close> by simp
  14.111 -qed
  14.112 -
  14.113 -lemma card_bdd_nat_set_le: "card { y::nat. y \<le> x} = Suc x"
  14.114 -proof -
  14.115 -  have "{y::nat. y \<le> x} = { y::nat. y < Suc x}"
  14.116 -    by auto
  14.117 -  then show ?thesis by (auto simp add: card_bdd_nat_set_l)
  14.118 -qed
  14.119 -
  14.120 -lemma card_bdd_int_set_l: "0 \<le> (n::int) ==> card {y. 0 \<le> y & y < n} = nat n"
  14.121 -proof -
  14.122 -  assume "0 \<le> n"
  14.123 -  have "inj_on (%y. int y) {y. y < nat n}"
  14.124 -    by (auto simp add: inj_on_def)
  14.125 -  hence "card (int ` {y. y < nat n}) = card {y. y < nat n}"
  14.126 -    by (rule card_image)
  14.127 -  also from \<open>0 \<le> n\<close> have "int ` {y. y < nat n} = {y. 0 \<le> y & y < n}"
  14.128 -    apply (auto simp add: zless_nat_eq_int_zless image_def)
  14.129 -    apply (rule_tac x = "nat x" in exI)
  14.130 -    apply (auto simp add: nat_0_le)
  14.131 -    done
  14.132 -  also have "card {y. y < nat n} = nat n"
  14.133 -    by (rule card_bdd_nat_set_l)
  14.134 -  finally show "card {y. 0 \<le> y & y < n} = nat n" .
  14.135 -qed
  14.136 -
  14.137 -lemma card_bdd_int_set_le: "0 \<le> (n::int) ==> card {y. 0 \<le> y & y \<le> n} =
  14.138 -  nat n + 1"
  14.139 -proof -
  14.140 -  assume "0 \<le> n"
  14.141 -  moreover have "{y. 0 \<le> y & y \<le> n} = {y. 0 \<le> y & y < n+1}" by auto
  14.142 -  ultimately show ?thesis
  14.143 -    using card_bdd_int_set_l [of "n + 1"]
  14.144 -    by (auto simp add: nat_add_distrib)
  14.145 -qed
  14.146 -
  14.147 -lemma card_bdd_int_set_l_le: "0 \<le> (n::int) ==>
  14.148 -    card {x. 0 < x & x \<le> n} = nat n"
  14.149 -proof -
  14.150 -  assume "0 \<le> n"
  14.151 -  have "inj_on (%x. x+1) {x. 0 \<le> x & x < n}"
  14.152 -    by (auto simp add: inj_on_def)
  14.153 -  hence "card ((%x. x+1) ` {x. 0 \<le> x & x < n}) =
  14.154 -     card {x. 0 \<le> x & x < n}"
  14.155 -    by (rule card_image)
  14.156 -  also from \<open>0 \<le> n\<close> have "... = nat n"
  14.157 -    by (rule card_bdd_int_set_l)
  14.158 -  also have "(%x. x + 1) ` {x. 0 \<le> x & x < n} = {x. 0 < x & x<= n}"
  14.159 -    apply (auto simp add: image_def)
  14.160 -    apply (rule_tac x = "x - 1" in exI)
  14.161 -    apply arith
  14.162 -    done
  14.163 -  finally show "card {x. 0 < x & x \<le> n} = nat n" .
  14.164 -qed
  14.165 -
  14.166 -lemma card_bdd_int_set_l_l: "0 < (n::int) ==>
  14.167 -  card {x. 0 < x & x < n} = nat n - 1"
  14.168 -proof -
  14.169 -  assume "0 < n"
  14.170 -  moreover have "{x. 0 < x & x < n} = {x. 0 < x & x \<le> n - 1}"
  14.171 -    by simp
  14.172 -  ultimately show ?thesis
  14.173 -    using insert card_bdd_int_set_l_le [of "n - 1"]
  14.174 -    by (auto simp add: nat_diff_distrib)
  14.175 -qed
  14.176 -
  14.177 -lemma int_card_bdd_int_set_l_l: "0 < n ==>
  14.178 -    int(card {x. 0 < x & x < n}) = n - 1"
  14.179 -  apply (auto simp add: card_bdd_int_set_l_l)
  14.180 -  done
  14.181 -
  14.182 -lemma int_card_bdd_int_set_l_le: "0 \<le> n ==>
  14.183 -    int(card {x. 0 < x & x \<le> n}) = n"
  14.184 -  by (auto simp add: card_bdd_int_set_l_le)
  14.185 -
  14.186 -
  14.187 -end
    15.1 --- a/src/HOL/Old_Number_Theory/Gauss.thy	Tue Oct 18 07:04:08 2016 +0200
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,504 +0,0 @@
    15.4 -(*  Title:      HOL/Old_Number_Theory/Gauss.thy
    15.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
    15.6 -*)
    15.7 -
    15.8 -section \<open>Gauss' Lemma\<close>
    15.9 -
   15.10 -theory Gauss
   15.11 -imports Euler
   15.12 -begin
   15.13 -
   15.14 -locale GAUSS =
   15.15 -  fixes p :: "int"
   15.16 -  fixes a :: "int"
   15.17 -
   15.18 -  assumes p_prime: "zprime p"
   15.19 -  assumes p_g_2: "2 < p"
   15.20 -  assumes p_a_relprime: "~[a = 0](mod p)"
   15.21 -  assumes a_nonzero:    "0 < a"
   15.22 -begin
   15.23 -
   15.24 -definition "A = {(x::int). 0 < x & x \<le> ((p - 1) div 2)}"
   15.25 -definition "B = (%x. x * a) ` A"
   15.26 -definition "C = StandardRes p ` B"
   15.27 -definition "D = C \<inter> {x. x \<le> ((p - 1) div 2)}"
   15.28 -definition "E = C \<inter> {x. ((p - 1) div 2) < x}"
   15.29 -definition "F = (%x. (p - x)) ` E"
   15.30 -
   15.31 -
   15.32 -subsection \<open>Basic properties of p\<close>
   15.33 -
   15.34 -lemma p_odd: "p \<in> zOdd"
   15.35 -  by (auto simp add: p_prime p_g_2 zprime_zOdd_eq_grt_2)
   15.36 -
   15.37 -lemma p_g_0: "0 < p"
   15.38 -  using p_g_2 by auto
   15.39 -
   15.40 -lemma int_nat: "int (nat ((p - 1) div 2)) = (p - 1) div 2"
   15.41 -  using ListMem.insert p_g_2 by (auto simp add: pos_imp_zdiv_nonneg_iff)
   15.42 -
   15.43 -lemma p_minus_one_l: "(p - 1) div 2 < p"
   15.44 -proof -
   15.45 -  have "(p - 1) div 2 \<le> (p - 1) div 1"
   15.46 -    by (rule zdiv_mono2) (auto simp add: p_g_0)
   15.47 -  also have "\<dots> = p - 1" by simp
   15.48 -  finally show ?thesis by simp
   15.49 -qed
   15.50 -
   15.51 -lemma p_eq: "p = (2 * (p - 1) div 2) + 1"
   15.52 -  using nonzero_mult_div_cancel_left [of 2 "p - 1"] by auto
   15.53 -
   15.54 -
   15.55 -lemma (in -) zodd_imp_zdiv_eq: "x \<in> zOdd ==> 2 * (x - 1) div 2 = 2 * ((x - 1) div 2)"
   15.56 -  by (simp add: in_zEven_zOdd_iff)
   15.57 -
   15.58 -
   15.59 -lemma p_eq2: "p = (2 * ((p - 1) div 2)) + 1"
   15.60 -  apply (insert p_eq p_prime p_g_2 zprime_zOdd_eq_grt_2 [of p], auto)
   15.61 -  apply (frule zodd_imp_zdiv_eq, auto)
   15.62 -  done
   15.63 -
   15.64 -
   15.65 -subsection \<open>Basic Properties of the Gauss Sets\<close>
   15.66 -
   15.67 -lemma finite_A: "finite (A)"
   15.68 -by (auto simp add: A_def)
   15.69 -
   15.70 -lemma finite_B: "finite (B)"
   15.71 -by (auto simp add: B_def finite_A)
   15.72 -
   15.73 -lemma finite_C: "finite (C)"
   15.74 -by (auto simp add: C_def finite_B)
   15.75 -
   15.76 -lemma finite_D: "finite (D)"
   15.77 -by (auto simp add: D_def finite_C)
   15.78 -
   15.79 -lemma finite_E: "finite (E)"
   15.80 -by (auto simp add: E_def finite_C)
   15.81 -
   15.82 -lemma finite_F: "finite (F)"
   15.83 -by (auto simp add: F_def finite_E)
   15.84 -
   15.85 -lemma C_eq: "C = D \<union> E"
   15.86 -by (auto simp add: C_def D_def E_def)
   15.87 -
   15.88 -lemma A_card_eq: "card A = nat ((p - 1) div 2)"
   15.89 -  apply (auto simp add: A_def)
   15.90 -  apply (insert int_nat)
   15.91 -  apply (erule subst)
   15.92 -  apply (auto simp add: card_bdd_int_set_l_le)
   15.93 -  done
   15.94 -
   15.95 -lemma inj_on_xa_A: "inj_on (%x. x * a) A"
   15.96 -  using a_nonzero by (simp add: A_def inj_on_def)
   15.97 -
   15.98 -lemma A_res: "ResSet p A"
   15.99 -  apply (auto simp add: A_def ResSet_def)
  15.100 -  apply (rule_tac m = p in zcong_less_eq)
  15.101 -  apply (insert p_g_2, auto)
  15.102 -  done
  15.103 -
  15.104 -lemma B_res: "ResSet p B"
  15.105 -  apply (insert p_g_2 p_a_relprime p_minus_one_l)
  15.106 -  apply (auto simp add: B_def)
  15.107 -  apply (rule ResSet_image)
  15.108 -  apply (auto simp add: A_res)
  15.109 -  apply (auto simp add: A_def)
  15.110 -proof -
  15.111 -  fix x fix y
  15.112 -  assume a: "[x * a = y * a] (mod p)"
  15.113 -  assume b: "0 < x"
  15.114 -  assume c: "x \<le> (p - 1) div 2"
  15.115 -  assume d: "0 < y"
  15.116 -  assume e: "y \<le> (p - 1) div 2"
  15.117 -  from a p_a_relprime p_prime a_nonzero zcong_cancel [of p a x y]
  15.118 -  have "[x = y](mod p)"
  15.119 -    by (simp add: zprime_imp_zrelprime zcong_def p_g_0 order_le_less)
  15.120 -  with zcong_less_eq [of x y p] p_minus_one_l
  15.121 -      order_le_less_trans [of x "(p - 1) div 2" p]
  15.122 -      order_le_less_trans [of y "(p - 1) div 2" p] show "x = y"
  15.123 -    by (simp add: b c d e p_minus_one_l p_g_0)
  15.124 -qed
  15.125 -
  15.126 -lemma SR_B_inj: "inj_on (StandardRes p) B"
  15.127 -  apply (auto simp add: B_def StandardRes_def inj_on_def A_def)
  15.128 -proof -
  15.129 -  fix x fix y
  15.130 -  assume a: "x * a mod p = y * a mod p"
  15.131 -  assume b: "0 < x"
  15.132 -  assume c: "x \<le> (p - 1) div 2"
  15.133 -  assume d: "0 < y"
  15.134 -  assume e: "y \<le> (p - 1) div 2"
  15.135 -  assume f: "x \<noteq> y"
  15.136 -  from a have "[x * a = y * a](mod p)"
  15.137 -    by (simp add: zcong_zmod_eq p_g_0)
  15.138 -  with p_a_relprime p_prime a_nonzero zcong_cancel [of p a x y]
  15.139 -  have "[x = y](mod p)"
  15.140 -    by (simp add: zprime_imp_zrelprime zcong_def p_g_0 order_le_less)
  15.141 -  with zcong_less_eq [of x y p] p_minus_one_l
  15.142 -    order_le_less_trans [of x "(p - 1) div 2" p]
  15.143 -    order_le_less_trans [of y "(p - 1) div 2" p] have "x = y"
  15.144 -    by (simp add: b c d e p_minus_one_l p_g_0)
  15.145 -  then have False
  15.146 -    by (simp add: f)
  15.147 -  then show "a = 0"
  15.148 -    by simp
  15.149 -qed
  15.150 -
  15.151 -lemma inj_on_pminusx_E: "inj_on (%x. p - x) E"
  15.152 -  apply (auto simp add: E_def C_def B_def A_def)
  15.153 -  apply (rule_tac g = "%x. -1 * (x - p)" in inj_on_inverseI)
  15.154 -  apply auto
  15.155 -  done
  15.156 -
  15.157 -lemma A_ncong_p: "x \<in> A ==> ~[x = 0](mod p)"
  15.158 -  apply (auto simp add: A_def)
  15.159 -  apply (frule_tac m = p in zcong_not_zero)
  15.160 -  apply (insert p_minus_one_l)
  15.161 -  apply auto
  15.162 -  done
  15.163 -
  15.164 -lemma A_greater_zero: "x \<in> A ==> 0 < x"
  15.165 -  by (auto simp add: A_def)
  15.166 -
  15.167 -lemma B_ncong_p: "x \<in> B ==> ~[x = 0](mod p)"
  15.168 -  apply (auto simp add: B_def)
  15.169 -  apply (frule A_ncong_p)
  15.170 -  apply (insert p_a_relprime p_prime a_nonzero)
  15.171 -  apply (frule_tac a = xa and b = a in zcong_zprime_prod_zero_contra)
  15.172 -  apply (auto simp add: A_greater_zero)
  15.173 -  done
  15.174 -
  15.175 -lemma B_greater_zero: "x \<in> B ==> 0 < x"
  15.176 -  using a_nonzero by (auto simp add: B_def A_greater_zero)
  15.177 -
  15.178 -lemma C_ncong_p: "x \<in> C ==>  ~[x = 0](mod p)"
  15.179 -  apply (auto simp add: C_def)
  15.180 -  apply (frule B_ncong_p)
  15.181 -  apply (subgoal_tac "[xa = StandardRes p xa](mod p)")
  15.182 -  defer apply (simp add: StandardRes_prop1)
  15.183 -  apply (frule_tac a = xa and b = "StandardRes p xa" and c = 0 in zcong_trans)
  15.184 -  apply auto
  15.185 -  done
  15.186 -
  15.187 -lemma C_greater_zero: "y \<in> C ==> 0 < y"
  15.188 -  apply (auto simp add: C_def)
  15.189 -proof -
  15.190 -  fix x
  15.191 -  assume a: "x \<in> B"
  15.192 -  from p_g_0 have "0 \<le> StandardRes p x"
  15.193 -    by (simp add: StandardRes_lbound)
  15.194 -  moreover have "~[x = 0] (mod p)"
  15.195 -    by (simp add: a B_ncong_p)
  15.196 -  then have "StandardRes p x \<noteq> 0"
  15.197 -    by (simp add: StandardRes_prop3)
  15.198 -  ultimately show "0 < StandardRes p x"
  15.199 -    by (simp add: order_le_less)
  15.200 -qed
  15.201 -
  15.202 -lemma D_ncong_p: "x \<in> D ==> ~[x = 0](mod p)"
  15.203 -  by (auto simp add: D_def C_ncong_p)
  15.204 -
  15.205 -lemma E_ncong_p: "x \<in> E ==> ~[x = 0](mod p)"
  15.206 -  by (auto simp add: E_def C_ncong_p)
  15.207 -
  15.208 -lemma F_ncong_p: "x \<in> F ==> ~[x = 0](mod p)"
  15.209 -  apply (auto simp add: F_def)
  15.210 -proof -
  15.211 -  fix x assume a: "x \<in> E" assume b: "[p - x = 0] (mod p)"
  15.212 -  from E_ncong_p have "~[x = 0] (mod p)"
  15.213 -    by (simp add: a)
  15.214 -  moreover from a have "0 < x"
  15.215 -    by (simp add: a E_def C_greater_zero)
  15.216 -  moreover from a have "x < p"
  15.217 -    by (auto simp add: E_def C_def p_g_0 StandardRes_ubound)
  15.218 -  ultimately have "~[p - x = 0] (mod p)"
  15.219 -    by (simp add: zcong_not_zero)
  15.220 -  from this show False by (simp add: b)
  15.221 -qed
  15.222 -
  15.223 -lemma F_subset: "F \<subseteq> {x. 0 < x & x \<le> ((p - 1) div 2)}"
  15.224 -  apply (auto simp add: F_def E_def)
  15.225 -  apply (insert p_g_0)
  15.226 -  apply (frule_tac x = xa in StandardRes_ubound)
  15.227 -  apply (frule_tac x = x in StandardRes_ubound)
  15.228 -  apply (subgoal_tac "xa = StandardRes p xa")
  15.229 -  apply (auto simp add: C_def StandardRes_prop2 StandardRes_prop1)
  15.230 -proof -
  15.231 -  from zodd_imp_zdiv_eq p_prime p_g_2 zprime_zOdd_eq_grt_2 have
  15.232 -    "2 * (p - 1) div 2 = 2 * ((p - 1) div 2)"
  15.233 -    by simp
  15.234 -  with p_eq2 show " !!x. [| (p - 1) div 2 < StandardRes p x; x \<in> B |]
  15.235 -      ==> p - StandardRes p x \<le> (p - 1) div 2"
  15.236 -    by simp
  15.237 -qed
  15.238 -
  15.239 -lemma D_subset: "D \<subseteq> {x. 0 < x & x \<le> ((p - 1) div 2)}"
  15.240 -  by (auto simp add: D_def C_greater_zero)
  15.241 -
  15.242 -lemma F_eq: "F = {x. \<exists>y \<in> A. ( x = p - (StandardRes p (y*a)) & (p - 1) div 2 < StandardRes p (y*a))}"
  15.243 -  by (auto simp add: F_def E_def D_def C_def B_def A_def)
  15.244 -
  15.245 -lemma D_eq: "D = {x. \<exists>y \<in> A. ( x = StandardRes p (y*a) & StandardRes p (y*a) \<le> (p - 1) div 2)}"
  15.246 -  by (auto simp add: D_def C_def B_def A_def)
  15.247 -
  15.248 -lemma D_leq: "x \<in> D ==> x \<le> (p - 1) div 2"
  15.249 -  by (auto simp add: D_eq)
  15.250 -
  15.251 -lemma F_ge: "x \<in> F ==> x \<le> (p - 1) div 2"
  15.252 -  apply (auto simp add: F_eq A_def)
  15.253 -proof -
  15.254 -  fix y
  15.255 -  assume "(p - 1) div 2 < StandardRes p (y * a)"
  15.256 -  then have "p - StandardRes p (y * a) < p - ((p - 1) div 2)"
  15.257 -    by arith
  15.258 -  also from p_eq2 have "... = 2 * ((p - 1) div 2) + 1 - ((p - 1) div 2)"
  15.259 -    by auto
  15.260 -  also have "2 * ((p - 1) div 2) + 1 - (p - 1) div 2 = (p - 1) div 2 + 1"
  15.261 -    by arith
  15.262 -  finally show "p - StandardRes p (y * a) \<le> (p - 1) div 2"
  15.263 -    using zless_add1_eq [of "p - StandardRes p (y * a)" "(p - 1) div 2"] by auto
  15.264 -qed
  15.265 -
  15.266 -lemma all_A_relprime: "\<forall>x \<in> A. zgcd x p = 1"
  15.267 -  using p_prime p_minus_one_l by (auto simp add: A_def zless_zprime_imp_zrelprime)
  15.268 -
  15.269 -lemma A_prod_relprime: "zgcd (prod id A) p = 1"
  15.270 -by(rule all_relprime_prod_relprime[OF finite_A all_A_relprime])
  15.271 -
  15.272 -
  15.273 -subsection \<open>Relationships Between Gauss Sets\<close>
  15.274 -
  15.275 -lemma B_card_eq_A: "card B = card A"
  15.276 -  using finite_A by (simp add: finite_A B_def inj_on_xa_A card_image)
  15.277 -
  15.278 -lemma B_card_eq: "card B = nat ((p - 1) div 2)"
  15.279 -  by (simp add: B_card_eq_A A_card_eq)
  15.280 -
  15.281 -lemma F_card_eq_E: "card F = card E"
  15.282 -  using finite_E by (simp add: F_def inj_on_pminusx_E card_image)
  15.283 -
  15.284 -lemma C_card_eq_B: "card C = card B"
  15.285 -  apply (insert finite_B)
  15.286 -  apply (subgoal_tac "inj_on (StandardRes p) B")
  15.287 -  apply (simp add: B_def C_def card_image)
  15.288 -  apply (rule StandardRes_inj_on_ResSet)
  15.289 -  apply (simp add: B_res)
  15.290 -  done
  15.291 -
  15.292 -lemma D_E_disj: "D \<inter> E = {}"
  15.293 -  by (auto simp add: D_def E_def)
  15.294 -
  15.295 -lemma C_card_eq_D_plus_E: "card C = card D + card E"
  15.296 -  by (auto simp add: C_eq card_Un_disjoint D_E_disj finite_D finite_E)
  15.297 -
  15.298 -lemma C_prod_eq_D_times_E: "prod id E * prod id D = prod id C"
  15.299 -  apply (insert D_E_disj finite_D finite_E C_eq)
  15.300 -  apply (frule prod.union_disjoint [of D E id])
  15.301 -  apply auto
  15.302 -  done
  15.303 -
  15.304 -lemma C_B_zcong_prod: "[prod id C = prod id B] (mod p)"
  15.305 -  apply (auto simp add: C_def)
  15.306 -  apply (insert finite_B SR_B_inj)
  15.307 -  apply (frule prod.reindex [of "StandardRes p" B id])
  15.308 -  apply auto
  15.309 -  apply (rule prod_same_function_zcong)
  15.310 -  apply (auto simp add: StandardRes_prop1 zcong_sym p_g_0)
  15.311 -  done
  15.312 -
  15.313 -lemma F_Un_D_subset: "(F \<union> D) \<subseteq> A"
  15.314 -  apply (rule Un_least)
  15.315 -  apply (auto simp add: A_def F_subset D_subset)
  15.316 -  done
  15.317 -
  15.318 -lemma F_D_disj: "(F \<inter> D) = {}"
  15.319 -  apply (simp add: F_eq D_eq)
  15.320 -  apply (auto simp add: F_eq D_eq)
  15.321 -proof -
  15.322 -  fix y fix ya
  15.323 -  assume "p - StandardRes p (y * a) = StandardRes p (ya * a)"
  15.324 -  then have "p = StandardRes p (y * a) + StandardRes p (ya * a)"
  15.325 -    by arith
  15.326 -  moreover have "p dvd p"
  15.327 -    by auto
  15.328 -  ultimately have "p dvd (StandardRes p (y * a) + StandardRes p (ya * a))"
  15.329 -    by auto
  15.330 -  then have a: "[StandardRes p (y * a) + StandardRes p (ya * a) = 0] (mod p)"
  15.331 -    by (auto simp add: zcong_def)
  15.332 -  have "[y * a = StandardRes p (y * a)] (mod p)"
  15.333 -    by (simp only: zcong_sym StandardRes_prop1)
  15.334 -  moreover have "[ya * a = StandardRes p (ya * a)] (mod p)"
  15.335 -    by (simp only: zcong_sym StandardRes_prop1)
  15.336 -  ultimately have "[y * a + ya * a =
  15.337 -    StandardRes p (y * a) + StandardRes p (ya * a)] (mod p)"
  15.338 -    by (rule zcong_zadd)
  15.339 -  with a have "[y * a + ya * a = 0] (mod p)"
  15.340 -    apply (elim zcong_trans)
  15.341 -    by (simp only: zcong_refl)
  15.342 -  also have "y * a + ya * a = a * (y + ya)"
  15.343 -    by (simp add: distrib_left mult.commute)
  15.344 -  finally have "[a * (y + ya) = 0] (mod p)" .
  15.345 -  with p_prime a_nonzero zcong_zprime_prod_zero [of p a "y + ya"]
  15.346 -    p_a_relprime
  15.347 -  have a: "[y + ya = 0] (mod p)"
  15.348 -    by auto
  15.349 -  assume b: "y \<in> A" and c: "ya: A"
  15.350 -  with A_def have "0 < y + ya"
  15.351 -    by auto
  15.352 -  moreover from b c A_def have "y + ya \<le> (p - 1) div 2 + (p - 1) div 2"
  15.353 -    by auto
  15.354 -  moreover from b c p_eq2 A_def have "y + ya < p"
  15.355 -    by auto
  15.356 -  ultimately show False
  15.357 -    apply simp
  15.358 -    apply (frule_tac m = p in zcong_not_zero)
  15.359 -    apply (auto simp add: a)
  15.360 -    done
  15.361 -qed
  15.362 -
  15.363 -lemma F_Un_D_card: "card (F \<union> D) = nat ((p - 1) div 2)"
  15.364 -proof -
  15.365 -  have "card (F \<union> D) = card E + card D"
  15.366 -    by (auto simp add: finite_F finite_D F_D_disj
  15.367 -      card_Un_disjoint F_card_eq_E)
  15.368 -  then have "card (F \<union> D) = card C"
  15.369 -    by (simp add: C_card_eq_D_plus_E)
  15.370 -  from this show "card (F \<union> D) = nat ((p - 1) div 2)"
  15.371 -    by (simp add: C_card_eq_B B_card_eq)
  15.372 -qed
  15.373 -
  15.374 -lemma F_Un_D_eq_A: "F \<union> D = A"
  15.375 -  using finite_A F_Un_D_subset A_card_eq F_Un_D_card by (auto simp add: card_seteq)
  15.376 -
  15.377 -lemma prod_D_F_eq_prod_A:
  15.378 -    "(prod id D) * (prod id F) = prod id A"
  15.379 -  apply (insert F_D_disj finite_D finite_F)
  15.380 -  apply (frule prod.union_disjoint [of F D id])
  15.381 -  apply (auto simp add: F_Un_D_eq_A)
  15.382 -  done
  15.383 -
  15.384 -lemma prod_F_zcong:
  15.385 -  "[prod id F = ((-1) ^ (card E)) * (prod id E)] (mod p)"
  15.386 -proof -
  15.387 -  have "prod id F = prod id (op - p ` E)"
  15.388 -    by (auto simp add: F_def)
  15.389 -  then have "prod id F = prod (op - p) E"
  15.390 -    apply simp
  15.391 -    apply (insert finite_E inj_on_pminusx_E)
  15.392 -    apply (frule prod.reindex [of "minus p" E id])
  15.393 -    apply auto
  15.394 -    done
  15.395 -  then have one:
  15.396 -    "[prod id F = prod (StandardRes p o (op - p)) E] (mod p)"
  15.397 -    apply simp
  15.398 -    apply (insert p_g_0 finite_E StandardRes_prod)
  15.399 -    by (auto)
  15.400 -  moreover have a: "\<forall>x \<in> E. [p - x = 0 - x] (mod p)"
  15.401 -    apply clarify
  15.402 -    apply (insert zcong_id [of p])
  15.403 -    apply (rule_tac a = p and m = p and c = x and d = x in zcong_zdiff, auto)
  15.404 -    done
  15.405 -  moreover have b: "\<forall>x \<in> E. [StandardRes p (p - x) = p - x](mod p)"
  15.406 -    apply clarify
  15.407 -    apply (simp add: StandardRes_prop1 zcong_sym)
  15.408 -    done
  15.409 -  moreover have "\<forall>x \<in> E. [StandardRes p (p - x) = - x](mod p)"
  15.410 -    apply clarify
  15.411 -    apply (insert a b)
  15.412 -    apply (rule_tac b = "p - x" in zcong_trans, auto)
  15.413 -    done
  15.414 -  ultimately have c:
  15.415 -    "[prod (StandardRes p o (op - p)) E = prod (uminus) E](mod p)"
  15.416 -    apply simp
  15.417 -    using finite_E p_g_0
  15.418 -      prod_same_function_zcong [of E "StandardRes p o (op - p)" uminus p]
  15.419 -    by auto
  15.420 -  then have two: "[prod id F = prod (uminus) E](mod p)"
  15.421 -    apply (insert one c)
  15.422 -    apply (rule zcong_trans [of "prod id F"
  15.423 -                               "prod (StandardRes p o op - p) E" p
  15.424 -                               "prod uminus E"], auto)
  15.425 -    done
  15.426 -  also have "prod uminus E = (prod id E) * (-1)^(card E)"
  15.427 -    using finite_E by (induct set: finite) auto
  15.428 -  then have "prod uminus E = (-1) ^ (card E) * (prod id E)"
  15.429 -    by (simp add: mult.commute)
  15.430 -  with two show ?thesis
  15.431 -    by simp
  15.432 -qed
  15.433 -
  15.434 -
  15.435 -subsection \<open>Gauss' Lemma\<close>
  15.436 -
  15.437 -lemma aux: "prod id A * (- 1) ^ card E * a ^ card A * (- 1) ^ card E = prod id A * a ^ card A"
  15.438 -  by (auto simp add: finite_E neg_one_special)
  15.439 -
  15.440 -theorem pre_gauss_lemma:
  15.441 -  "[a ^ nat((p - 1) div 2) = (-1) ^ (card E)] (mod p)"
  15.442 -proof -
  15.443 -  have "[prod id A = prod id F * prod id D](mod p)"
  15.444 -    by (auto simp add: prod_D_F_eq_prod_A mult.commute cong del: prod.strong_cong)
  15.445 -  then have "[prod id A = ((-1)^(card E) * prod id E) *
  15.446 -      prod id D] (mod p)"
  15.447 -    by (rule zcong_trans) (auto simp add: prod_F_zcong zcong_scalar cong del: prod.strong_cong)
  15.448 -  then have "[prod id A = ((-1)^(card E) * prod id C)] (mod p)"
  15.449 -    apply (rule zcong_trans)
  15.450 -    apply (insert C_prod_eq_D_times_E, erule subst)
  15.451 -    apply (subst mult.assoc)
  15.452 -    apply auto
  15.453 -    done
  15.454 -  then have "[prod id A = ((-1)^(card E) * prod id B)] (mod p)"
  15.455 -    apply (rule zcong_trans)
  15.456 -    apply (simp add: C_B_zcong_prod zcong_scalar2 cong del: prod.strong_cong)
  15.457 -    done
  15.458 -  then have "[prod id A = ((-1)^(card E) *
  15.459 -    (prod id ((%x. x * a) ` A)))] (mod p)"
  15.460 -    by (simp add: B_def)
  15.461 -  then have "[prod id A = ((-1)^(card E) * (prod (%x. x * a) A))]
  15.462 -    (mod p)"
  15.463 -    by (simp add:finite_A inj_on_xa_A prod.reindex cong del: prod.strong_cong)
  15.464 -  moreover have "prod (%x. x * a) A =
  15.465 -    prod (%x. a) A * prod id A"
  15.466 -    using finite_A by (induct set: finite) auto
  15.467 -  ultimately have "[prod id A = ((-1)^(card E) * (prod (%x. a) A *
  15.468 -    prod id A))] (mod p)"
  15.469 -    by simp
  15.470 -  then have "[prod id A = ((-1)^(card E) * a^(card A) *
  15.471 -      prod id A)](mod p)"
  15.472 -    by (rule zcong_trans) (simp add: zcong_scalar2 zcong_scalar finite_A prod_constant mult.assoc)
  15.473 -  then have a: "[prod id A * (-1)^(card E) =
  15.474 -      ((-1)^(card E) * a^(card A) * prod id A * (-1)^(card E))](mod p)"
  15.475 -    by (rule zcong_scalar)
  15.476 -  then have "[prod id A * (-1)^(card E) = prod id A *
  15.477 -      (-1)^(card E) * a^(card A) * (-1)^(card E)](mod p)"
  15.478 -    by (rule zcong_trans) (simp add: a mult.commute mult.left_commute)
  15.479 -  then have "[prod id A * (-1)^(card E) = prod id A *
  15.480 -      a^(card A)](mod p)"
  15.481 -    by (rule zcong_trans) (simp add: aux cong del: prod.strong_cong)
  15.482 -  with this zcong_cancel2 [of p "prod id A" "(- 1) ^ card E" "a ^ card A"]
  15.483 -      p_g_0 A_prod_relprime have "[(- 1) ^ card E = a ^ card A](mod p)"
  15.484 -    by (simp add: order_less_imp_le)
  15.485 -  from this show ?thesis
  15.486 -    by (simp add: A_card_eq zcong_sym)
  15.487 -qed
  15.488 -
  15.489 -theorem gauss_lemma: "(Legendre a p) = (-1) ^ (card E)"
  15.490 -proof -
  15.491 -  from Euler_Criterion p_prime p_g_2 have
  15.492 -      "[(Legendre a p) = a^(nat (((p) - 1) div 2))] (mod p)"
  15.493 -    by auto
  15.494 -  moreover note pre_gauss_lemma
  15.495 -  ultimately have "[(Legendre a p) = (-1) ^ (card E)] (mod p)"
  15.496 -    by (rule zcong_trans)
  15.497 -  moreover from p_a_relprime have "(Legendre a p) = 1 | (Legendre a p) = (-1)"
  15.498 -    by (auto simp add: Legendre_def)
  15.499 -  moreover have "(-1::int) ^ (card E) = 1 | (-1::int) ^ (card E) = -1"
  15.500 -    by (rule neg_one_power)
  15.501 -  ultimately show ?thesis
  15.502 -    by (auto simp add: p_g_2 one_not_neg_one_mod_m zcong_sym)
  15.503 -qed
  15.504 -
  15.505 -end
  15.506 -
  15.507 -end
    16.1 --- a/src/HOL/Old_Number_Theory/Int2.thy	Tue Oct 18 07:04:08 2016 +0200
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,299 +0,0 @@
    16.4 -(*  Title:      HOL/Old_Number_Theory/Int2.thy
    16.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
    16.6 -*)
    16.7 -
    16.8 -section \<open>Integers: Divisibility and Congruences\<close>
    16.9 -
   16.10 -theory Int2
   16.11 -imports Finite2 WilsonRuss
   16.12 -begin
   16.13 -
   16.14 -definition MultInv :: "int => int => int"
   16.15 -  where "MultInv p x = x ^ nat (p - 2)"
   16.16 -
   16.17 -
   16.18 -subsection \<open>Useful lemmas about dvd and powers\<close>
   16.19 -
   16.20 -lemma zpower_zdvd_prop1:
   16.21 -  "0 < n \<Longrightarrow> p dvd y \<Longrightarrow> p dvd ((y::int) ^ n)"
   16.22 -  by (induct n) (auto simp add: dvd_mult2 [of p y])
   16.23 -
   16.24 -lemma zdvd_bounds: "n dvd m ==> m \<le> (0::int) | n \<le> m"
   16.25 -proof -
   16.26 -  assume "n dvd m"
   16.27 -  then have "~(0 < m & m < n)"
   16.28 -    using zdvd_not_zless [of m n] by auto
   16.29 -  then show ?thesis by auto
   16.30 -qed
   16.31 -
   16.32 -lemma zprime_zdvd_zmult_better: "[| zprime p;  p dvd (m * n) |] ==>
   16.33 -    (p dvd m) | (p dvd n)"
   16.34 -  apply (cases "0 \<le> m")
   16.35 -  apply (simp add: zprime_zdvd_zmult)
   16.36 -  apply (insert zprime_zdvd_zmult [of "-m" p n])
   16.37 -  apply auto
   16.38 -  done
   16.39 -
   16.40 -lemma zpower_zdvd_prop2:
   16.41 -    "zprime p \<Longrightarrow> p dvd ((y::int) ^ n) \<Longrightarrow> 0 < n \<Longrightarrow> p dvd y"
   16.42 -  apply (induct n)
   16.43 -   apply simp
   16.44 -  apply (frule zprime_zdvd_zmult_better)
   16.45 -   apply simp
   16.46 -  apply (force simp del:dvd_mult)
   16.47 -  done
   16.48 -
   16.49 -lemma div_prop1:
   16.50 -  assumes "0 < z" and "(x::int) < y * z"
   16.51 -  shows "x div z < y"
   16.52 -proof -
   16.53 -  from \<open>0 < z\<close> have modth: "x mod z \<ge> 0" by simp
   16.54 -  have "(x div z) * z \<le> (x div z) * z" by simp
   16.55 -  then have "(x div z) * z \<le> (x div z) * z + x mod z" using modth by arith 
   16.56 -  also have "\<dots> = x"
   16.57 -    by (auto simp add: mult_div_mod_eq ac_simps)
   16.58 -  also note \<open>x < y * z\<close>
   16.59 -  finally show ?thesis
   16.60 -    apply (auto simp add: mult_less_cancel_right)
   16.61 -    using assms apply arith
   16.62 -    done
   16.63 -qed
   16.64 -
   16.65 -lemma div_prop2:
   16.66 -  assumes "0 < z" and "(x::int) < (y * z) + z"
   16.67 -  shows "x div z \<le> y"
   16.68 -proof -
   16.69 -  from assms have "x < (y + 1) * z" by (auto simp add: int_distrib)
   16.70 -  then have "x div z < y + 1"
   16.71 -    apply (rule_tac y = "y + 1" in div_prop1)
   16.72 -    apply (auto simp add: \<open>0 < z\<close>)
   16.73 -    done
   16.74 -  then show ?thesis by auto
   16.75 -qed
   16.76 -
   16.77 -lemma zdiv_leq_prop: assumes "0 < y" shows "y * (x div y) \<le> (x::int)"
   16.78 -proof-
   16.79 -  from mult_div_mod_eq [symmetric] have "x = y * (x div y) + x mod y" by auto
   16.80 -  moreover have "0 \<le> x mod y" by (auto simp add: assms)
   16.81 -  ultimately show ?thesis by arith
   16.82 -qed
   16.83 -
   16.84 -
   16.85 -subsection \<open>Useful properties of congruences\<close>
   16.86 -
   16.87 -lemma zcong_eq_zdvd_prop: "[x = 0](mod p) = (p dvd x)"
   16.88 -  by (auto simp add: zcong_def)
   16.89 -
   16.90 -lemma zcong_id: "[m = 0] (mod m)"
   16.91 -  by (auto simp add: zcong_def)
   16.92 -
   16.93 -lemma zcong_shift: "[a = b] (mod m) ==> [a + c = b + c] (mod m)"
   16.94 -  by (auto simp add: zcong_zadd)
   16.95 -
   16.96 -lemma zcong_zpower: "[x = y](mod m) ==> [x^z = y^z](mod m)"
   16.97 -  by (induct z) (auto simp add: zcong_zmult)
   16.98 -
   16.99 -lemma zcong_eq_trans: "[| [a = b](mod m); b = c; [c = d](mod m) |] ==>
  16.100 -    [a = d](mod m)"
  16.101 -  apply (erule zcong_trans)
  16.102 -  apply simp
  16.103 -  done
  16.104 -
  16.105 -lemma aux1: "a - b = (c::int) ==> a = c + b"
  16.106 -  by auto
  16.107 -
  16.108 -lemma zcong_zmult_prop1: "[a = b](mod m) ==> ([c = a * d](mod m) =
  16.109 -    [c = b * d] (mod m))"
  16.110 -  apply (auto simp add: zcong_def dvd_def)
  16.111 -  apply (rule_tac x = "ka + k * d" in exI)
  16.112 -  apply (drule aux1)+
  16.113 -  apply (auto simp add: int_distrib)
  16.114 -  apply (rule_tac x = "ka - k * d" in exI)
  16.115 -  apply (drule aux1)+
  16.116 -  apply (auto simp add: int_distrib)
  16.117 -  done
  16.118 -
  16.119 -lemma zcong_zmult_prop2: "[a = b](mod m) ==>
  16.120 -    ([c = d * a](mod m) = [c = d * b] (mod m))"
  16.121 -  by (auto simp add: ac_simps zcong_zmult_prop1)
  16.122 -
  16.123 -lemma zcong_zmult_prop3: "[| zprime p; ~[x = 0] (mod p);
  16.124 -    ~[y = 0] (mod p) |] ==> ~[x * y = 0] (mod p)"
  16.125 -  apply (auto simp add: zcong_def)
  16.126 -  apply (drule zprime_zdvd_zmult_better, auto)
  16.127 -  done
  16.128 -
  16.129 -lemma zcong_less_eq: "[| 0 < x; 0 < y; 0 < m; [x = y] (mod m);
  16.130 -    x < m; y < m |] ==> x = y"
  16.131 -  by (metis zcong_not zcong_sym less_linear)
  16.132 -
  16.133 -lemma zcong_neg_1_impl_ne_1:
  16.134 -  assumes "2 < p" and "[x = -1] (mod p)"
  16.135 -  shows "~([x = 1] (mod p))"
  16.136 -proof
  16.137 -  assume "[x = 1] (mod p)"
  16.138 -  with assms have "[1 = -1] (mod p)"
  16.139 -    apply (auto simp add: zcong_sym)
  16.140 -    apply (drule zcong_trans, auto)
  16.141 -    done
  16.142 -  then have "[1 + 1 = -1 + 1] (mod p)"
  16.143 -    by (simp only: zcong_shift)
  16.144 -  then have "[2 = 0] (mod p)"
  16.145 -    by auto
  16.146 -  then have "p dvd 2"
  16.147 -    by (auto simp add: dvd_def zcong_def)
  16.148 -  with \<open>2 < p\<close> show False
  16.149 -    by (auto simp add: zdvd_not_zless)
  16.150 -qed
  16.151 -
  16.152 -lemma zcong_zero_equiv_div: "[a = 0] (mod m) = (m dvd a)"
  16.153 -  by (auto simp add: zcong_def)
  16.154 -
  16.155 -lemma zcong_zprime_prod_zero: "[| zprime p; 0 < a |] ==>
  16.156 -    [a * b = 0] (mod p) ==> [a = 0] (mod p) | [b = 0] (mod p)"
  16.157 -  by (auto simp add: zcong_zero_equiv_div zprime_zdvd_zmult)
  16.158 -
  16.159 -lemma zcong_zprime_prod_zero_contra: "[| zprime p; 0 < a |] ==>
  16.160 -  ~[a = 0](mod p) & ~[b = 0](mod p) ==> ~[a * b = 0] (mod p)"
  16.161 -  apply auto
  16.162 -  apply (frule_tac a = a and b = b and p = p in zcong_zprime_prod_zero)
  16.163 -  apply auto
  16.164 -  done
  16.165 -
  16.166 -lemma zcong_not_zero: "[| 0 < x; x < m |] ==> ~[x = 0] (mod m)"
  16.167 -  by (auto simp add: zcong_zero_equiv_div zdvd_not_zless)
  16.168 -
  16.169 -lemma zcong_zero: "[| 0 \<le> x; x < m; [x = 0](mod m) |] ==> x = 0"
  16.170 -  apply (drule order_le_imp_less_or_eq, auto)
  16.171 -  apply (frule_tac m = m in zcong_not_zero)
  16.172 -  apply auto
  16.173 -  done
  16.174 -
  16.175 -lemma all_relprime_prod_relprime: "[| finite A; \<forall>x \<in> A. zgcd x y = 1 |]
  16.176 -    ==> zgcd (prod id A) y = 1"
  16.177 -  by (induct set: finite) (auto simp add: zgcd_zgcd_zmult)
  16.178 -
  16.179 -
  16.180 -subsection \<open>Some properties of MultInv\<close>
  16.181 -
  16.182 -lemma MultInv_prop1: "[| 2 < p; [x = y] (mod p) |] ==>
  16.183 -    [(MultInv p x) = (MultInv p y)] (mod p)"
  16.184 -  by (auto simp add: MultInv_def zcong_zpower)
  16.185 -
  16.186 -lemma MultInv_prop2: "[| 2 < p; zprime p; ~([x = 0](mod p)) |] ==>
  16.187 -  [(x * (MultInv p x)) = 1] (mod p)"
  16.188 -proof (simp add: MultInv_def zcong_eq_zdvd_prop)
  16.189 -  assume 1: "2 < p" and 2: "zprime p" and 3: "~ p dvd x"
  16.190 -  have "x * x ^ nat (p - 2) = x ^ (nat (p - 2) + 1)"
  16.191 -    by auto
  16.192 -  also from 1 have "nat (p - 2) + 1 = nat (p - 2 + 1)"
  16.193 -    by (simp only: nat_add_distrib)
  16.194 -  also have "p - 2 + 1 = p - 1" by arith
  16.195 -  finally have "[x * x ^ nat (p - 2) = x ^ nat (p - 1)] (mod p)"
  16.196 -    by (rule ssubst, auto)
  16.197 -  also from 2 3 have "[x ^ nat (p - 1) = 1] (mod p)"
  16.198 -    by (auto simp add: Little_Fermat)
  16.199 -  finally (zcong_trans) show "[x * x ^ nat (p - 2) = 1] (mod p)" .
  16.200 -qed
  16.201 -
  16.202 -lemma MultInv_prop2a: "[| 2 < p; zprime p; ~([x = 0](mod p)) |] ==>
  16.203 -    [(MultInv p x) * x = 1] (mod p)"
  16.204 -  by (auto simp add: MultInv_prop2 ac_simps)
  16.205 -
  16.206 -lemma aux_1: "2 < p ==> ((nat p) - 2) = (nat (p - 2))"
  16.207 -  by (simp add: nat_diff_distrib)
  16.208 -
  16.209 -lemma aux_2: "2 < p ==> 0 < nat (p - 2)"
  16.210 -  by auto
  16.211 -
  16.212 -lemma MultInv_prop3: "[| 2 < p; zprime p; ~([x = 0](mod p)) |] ==>
  16.213 -    ~([MultInv p x = 0](mod p))"
  16.214 -  apply (auto simp add: MultInv_def zcong_eq_zdvd_prop aux_1)
  16.215 -  apply (drule aux_2)
  16.216 -  apply (drule zpower_zdvd_prop2, auto)
  16.217 -  done
  16.218 -
  16.219 -lemma aux__1: "[| 2 < p; zprime p; ~([x = 0](mod p))|] ==>
  16.220 -    [(MultInv p (MultInv p x)) = (x * (MultInv p x) *
  16.221 -      (MultInv p (MultInv p x)))] (mod p)"
  16.222 -  apply (drule MultInv_prop2, auto)
  16.223 -  apply (drule_tac k = "MultInv p (MultInv p x)" in zcong_scalar, auto)
  16.224 -  apply (auto simp add: zcong_sym)
  16.225 -  done
  16.226 -
  16.227 -lemma aux__2: "[| 2 < p; zprime p; ~([x = 0](mod p))|] ==>
  16.228 -    [(x * (MultInv p x) * (MultInv p (MultInv p x))) = x] (mod p)"
  16.229 -  apply (frule MultInv_prop3, auto)
  16.230 -  apply (insert MultInv_prop2 [of p "MultInv p x"], auto)
  16.231 -  apply (drule MultInv_prop2, auto)
  16.232 -  apply (drule_tac k = x in zcong_scalar2, auto)
  16.233 -  apply (auto simp add: ac_simps)
  16.234 -  done
  16.235 -
  16.236 -lemma MultInv_prop4: "[| 2 < p; zprime p; ~([x = 0](mod p)) |] ==>
  16.237 -    [(MultInv p (MultInv p x)) = x] (mod p)"
  16.238 -  apply (frule aux__1, auto)
  16.239 -  apply (drule aux__2, auto)
  16.240 -  apply (drule zcong_trans, auto)
  16.241 -  done
  16.242 -
  16.243 -lemma MultInv_prop5: "[| 2 < p; zprime p; ~([x = 0](mod p));
  16.244 -    ~([y = 0](mod p)); [(MultInv p x) = (MultInv p y)] (mod p) |] ==>
  16.245 -    [x = y] (mod p)"
  16.246 -  apply (drule_tac a = "MultInv p x" and b = "MultInv p y" and
  16.247 -    m = p and k = x in zcong_scalar)
  16.248 -  apply (insert MultInv_prop2 [of p x], simp)
  16.249 -  apply (auto simp only: zcong_sym [of "MultInv p x * x"])
  16.250 -  apply (auto simp add: ac_simps)
  16.251 -  apply (drule zcong_trans, auto)
  16.252 -  apply (drule_tac a = "x * MultInv p y" and k = y in zcong_scalar, auto)
  16.253 -  apply (insert MultInv_prop2a [of p y], auto simp add: ac_simps)
  16.254 -  apply (insert zcong_zmult_prop2 [of "y * MultInv p y" 1 p y x])
  16.255 -  apply (auto simp add: zcong_sym)
  16.256 -  done
  16.257 -
  16.258 -lemma MultInv_zcong_prop1: "[| 2 < p; [j = k] (mod p) |] ==>
  16.259 -    [a * MultInv p j = a * MultInv p k] (mod p)"
  16.260 -  by (drule MultInv_prop1, auto simp add: zcong_scalar2)
  16.261 -
  16.262 -lemma aux___1: "[j = a * MultInv p k] (mod p) ==>
  16.263 -    [j * k = a * MultInv p k * k] (mod p)"
  16.264 -  by (auto simp add: zcong_scalar)
  16.265 -
  16.266 -lemma aux___2: "[|2 < p; zprime p; ~([k = 0](mod p));
  16.267 -    [j * k = a * MultInv p k * k] (mod p) |] ==> [j * k = a] (mod p)"
  16.268 -  apply (insert MultInv_prop2a [of p k] zcong_zmult_prop2
  16.269 -    [of "MultInv p k * k" 1 p "j * k" a])
  16.270 -  apply (auto simp add: ac_simps)
  16.271 -  done
  16.272 -
  16.273 -lemma aux___3: "[j * k = a] (mod p) ==> [(MultInv p j) * j * k =
  16.274 -     (MultInv p j) * a] (mod p)"
  16.275 -  by (auto simp add: mult.assoc zcong_scalar2)
  16.276 -
  16.277 -lemma aux___4: "[|2 < p; zprime p; ~([j = 0](mod p));
  16.278 -    [(MultInv p j) * j * k = (MultInv p j) * a] (mod p) |]
  16.279 -       ==> [k = a * (MultInv p j)] (mod p)"
  16.280 -  apply (insert MultInv_prop2a [of p j] zcong_zmult_prop1
  16.281 -    [of "MultInv p j * j" 1 p "MultInv p j * a" k])
  16.282 -  apply (auto simp add: ac_simps zcong_sym)
  16.283 -  done
  16.284 -
  16.285 -lemma MultInv_zcong_prop2: "[| 2 < p; zprime p; ~([k = 0](mod p));
  16.286 -    ~([j = 0](mod p)); [j = a * MultInv p k] (mod p) |] ==>
  16.287 -    [k = a * MultInv p j] (mod p)"
  16.288 -  apply (drule aux___1)
  16.289 -  apply (frule aux___2, auto)
  16.290 -  by (drule aux___3, drule aux___4, auto)
  16.291 -
  16.292 -lemma MultInv_zcong_prop3: "[| 2 < p; zprime p; ~([a = 0](mod p));
  16.293 -    ~([k = 0](mod p)); ~([j = 0](mod p));
  16.294 -    [a * MultInv p j = a * MultInv p k] (mod p) |] ==>
  16.295 -      [j = k] (mod p)"
  16.296 -  apply (auto simp add: zcong_eq_zdvd_prop [of a p])
  16.297 -  apply (frule zprime_imp_zrelprime, auto)
  16.298 -  apply (insert zcong_cancel2 [of p a "MultInv p j" "MultInv p k"], auto)
  16.299 -  apply (drule MultInv_prop5, auto)
  16.300 -  done
  16.301 -
  16.302 -end
    17.1 --- a/src/HOL/Old_Number_Theory/IntFact.thy	Tue Oct 18 07:04:08 2016 +0200
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,90 +0,0 @@
    17.4 -(*  Title:      HOL/Old_Number_Theory/IntFact.thy
    17.5 -    Author:     Thomas M. Rasmussen
    17.6 -    Copyright   2000  University of Cambridge
    17.7 -*)
    17.8 -
    17.9 -section \<open>Factorial on integers\<close>
   17.10 -
   17.11 -theory IntFact
   17.12 -imports IntPrimes
   17.13 -begin
   17.14 -
   17.15 -text \<open>
   17.16 -  Factorial on integers and recursively defined set including all
   17.17 -  Integers from \<open>2\<close> up to \<open>a\<close>.  Plus definition of product
   17.18 -  of finite set.
   17.19 -
   17.20 -  \bigskip
   17.21 -\<close>
   17.22 -
   17.23 -fun zfact :: "int => int"
   17.24 -  where "zfact n = (if n \<le> 0 then 1 else n * zfact (n - 1))"
   17.25 -
   17.26 -fun d22set :: "int => int set"
   17.27 -  where "d22set a = (if 1 < a then insert a (d22set (a - 1)) else {})"
   17.28 -
   17.29 -
   17.30 -text \<open>
   17.31 -  \medskip @{term d22set} --- recursively defined set including all
   17.32 -  integers from \<open>2\<close> up to \<open>a\<close>
   17.33 -\<close>
   17.34 -
   17.35 -declare d22set.simps [simp del]
   17.36 -
   17.37 -
   17.38 -lemma d22set_induct:
   17.39 -  assumes "!!a. P {} a"
   17.40 -    and "!!a. 1 < (a::int) ==> P (d22set (a - 1)) (a - 1) ==> P (d22set a) a"
   17.41 -  shows "P (d22set u) u"
   17.42 -  apply (rule d22set.induct)
   17.43 -  apply (case_tac "1 < a")
   17.44 -   apply (rule_tac assms)
   17.45 -    apply (simp_all (no_asm_simp))
   17.46 -  apply (simp_all (no_asm_simp) add: d22set.simps assms)
   17.47 -  done
   17.48 -
   17.49 -lemma d22set_g_1 [rule_format]: "b \<in> d22set a --> 1 < b"
   17.50 -  apply (induct a rule: d22set_induct)
   17.51 -   apply simp
   17.52 -  apply (subst d22set.simps)
   17.53 -  apply auto
   17.54 -  done
   17.55 -
   17.56 -lemma d22set_le [rule_format]: "b \<in> d22set a --> b \<le> a"
   17.57 -  apply (induct a rule: d22set_induct)
   17.58 -  apply simp
   17.59 -   apply (subst d22set.simps)
   17.60 -   apply auto
   17.61 -  done
   17.62 -
   17.63 -lemma d22set_le_swap: "a < b ==> b \<notin> d22set a"
   17.64 -  by (auto dest: d22set_le)
   17.65 -
   17.66 -lemma d22set_mem: "1 < b \<Longrightarrow> b \<le> a \<Longrightarrow> b \<in> d22set a"
   17.67 -  apply (induct a rule: d22set.induct)
   17.68 -  apply auto
   17.69 -  apply (subst d22set.simps)
   17.70 -  apply (case_tac "b < a", auto)
   17.71 -  done
   17.72 -
   17.73 -lemma d22set_fin: "finite (d22set a)"
   17.74 -  apply (induct a rule: d22set_induct)
   17.75 -   prefer 2
   17.76 -   apply (subst d22set.simps)
   17.77 -   apply auto
   17.78 -  done
   17.79 -
   17.80 -
   17.81 -declare zfact.simps [simp del]
   17.82 -
   17.83 -lemma d22set_prod_zfact: "\<Prod>(d22set a) = zfact a"
   17.84 -  apply (induct a rule: d22set.induct)
   17.85 -  apply (subst d22set.simps)
   17.86 -  apply (subst zfact.simps)
   17.87 -  apply (case_tac "1 < a")
   17.88 -   prefer 2
   17.89 -   apply (simp add: d22set.simps zfact.simps)
   17.90 -  apply (simp add: d22set_fin d22set_le_swap)
   17.91 -  done
   17.92 -
   17.93 -end
    18.1 --- a/src/HOL/Old_Number_Theory/IntPrimes.thy	Tue Oct 18 07:04:08 2016 +0200
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,412 +0,0 @@
    18.4 -(*  Title:      HOL/Old_Number_Theory/IntPrimes.thy
    18.5 -    Author:     Thomas M. Rasmussen
    18.6 -    Copyright   2000  University of Cambridge
    18.7 -*)
    18.8 -
    18.9 -section \<open>Divisibility and prime numbers (on integers)\<close>
   18.10 -
   18.11 -theory IntPrimes
   18.12 -imports Primes
   18.13 -begin
   18.14 -
   18.15 -text \<open>
   18.16 -  The \<open>dvd\<close> relation, GCD, Euclid's extended algorithm, primes,
   18.17 -  congruences (all on the Integers).  Comparable to theory \<open>Primes\<close>, but \<open>dvd\<close> is included here as it is not present in
   18.18 -  main HOL.  Also includes extended GCD and congruences not present in
   18.19 -  \<open>Primes\<close>.
   18.20 -\<close>
   18.21 -
   18.22 -
   18.23 -subsection \<open>Definitions\<close>
   18.24 -
   18.25 -fun xzgcda :: "int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int => (int * int * int)"
   18.26 -where
   18.27 -  "xzgcda m n r' r s' s t' t =
   18.28 -        (if r \<le> 0 then (r', s', t')
   18.29 -         else xzgcda m n r (r' mod r) 
   18.30 -                      s (s' - (r' div r) * s) 
   18.31 -                      t (t' - (r' div r) * t))"
   18.32 -
   18.33 -definition zprime :: "int \<Rightarrow> bool"
   18.34 -  where "zprime p = (1 < p \<and> (\<forall>m. 0 <= m & m dvd p --> m = 1 \<or> m = p))"
   18.35 -
   18.36 -definition xzgcd :: "int => int => int * int * int"
   18.37 -  where "xzgcd m n = xzgcda m n m n 1 0 0 1"
   18.38 -
   18.39 -definition zcong :: "int => int => int => bool"  ("(1[_ = _] '(mod _'))")
   18.40 -  where "[a = b] (mod m) = (m dvd (a - b))"
   18.41 -
   18.42 -
   18.43 -subsection \<open>Euclid's Algorithm and GCD\<close>
   18.44 -
   18.45 -
   18.46 -lemma zrelprime_zdvd_zmult_aux:
   18.47 -     "zgcd n k = 1 ==> k dvd m * n ==> 0 \<le> m ==> k dvd m"
   18.48 -    by (metis abs_of_nonneg dvd_triv_right zgcd_greatest_iff zgcd_zmult_distrib2_abs mult_1_right)
   18.49 -
   18.50 -lemma zrelprime_zdvd_zmult: "zgcd n k = 1 ==> k dvd m * n ==> k dvd m"
   18.51 -  apply (case_tac "0 \<le> m")
   18.52 -   apply (blast intro: zrelprime_zdvd_zmult_aux)
   18.53 -  apply (subgoal_tac "k dvd -m")
   18.54 -   apply (rule_tac [2] zrelprime_zdvd_zmult_aux, auto)
   18.55 -  done
   18.56 -
   18.57 -lemma zgcd_geq_zero: "0 <= zgcd x y"
   18.58 -  by (auto simp add: zgcd_def)
   18.59 -
   18.60 -text\<open>This is merely a sanity check on zprime, since the previous version
   18.61 -      denoted the empty set.\<close>
   18.62 -lemma "zprime 2"
   18.63 -  apply (auto simp add: zprime_def) 
   18.64 -  apply (frule zdvd_imp_le, simp) 
   18.65 -  apply (auto simp add: order_le_less dvd_def) 
   18.66 -  done
   18.67 -
   18.68 -lemma zprime_imp_zrelprime:
   18.69 -    "zprime p ==> \<not> p dvd n ==> zgcd n p = 1"
   18.70 -  apply (auto simp add: zprime_def)
   18.71 -  apply (metis zgcd_geq_zero zgcd_zdvd1 zgcd_zdvd2)
   18.72 -  done
   18.73 -
   18.74 -lemma zless_zprime_imp_zrelprime:
   18.75 -    "zprime p ==> 0 < n ==> n < p ==> zgcd n p = 1"
   18.76 -  apply (erule zprime_imp_zrelprime)
   18.77 -  apply (erule zdvd_not_zless, assumption)
   18.78 -  done
   18.79 -
   18.80 -lemma zprime_zdvd_zmult:
   18.81 -    "0 \<le> (m::int) ==> zprime p ==> p dvd m * n ==> p dvd m \<or> p dvd n"
   18.82 -  by (metis zgcd_zdvd1 zgcd_zdvd2 zgcd_pos zprime_def zrelprime_dvd_mult)
   18.83 -
   18.84 -lemma zgcd_zadd_zmult [simp]: "zgcd (m + n * k) n = zgcd m n"
   18.85 -  apply (rule zgcd_eq [THEN trans])
   18.86 -  apply (simp add: mod_add_eq)
   18.87 -  apply (rule zgcd_eq [symmetric])
   18.88 -  done
   18.89 -
   18.90 -lemma zgcd_zdvd_zgcd_zmult: "zgcd m n dvd zgcd (k * m) n"
   18.91 -by (simp add: zgcd_greatest_iff)
   18.92 -
   18.93 -lemma zgcd_zmult_zdvd_zgcd:
   18.94 -    "zgcd k n = 1 ==> zgcd (k * m) n dvd zgcd m n"
   18.95 -  apply (simp add: zgcd_greatest_iff)
   18.96 -  apply (rule_tac n = k in zrelprime_zdvd_zmult)
   18.97 -   prefer 2
   18.98 -   apply (simp add: mult.commute)
   18.99 -  apply (metis zgcd_1 zgcd_commute zgcd_left_commute)
  18.100 -  done
  18.101 -
  18.102 -lemma zgcd_zmult_cancel: "zgcd k n = 1 ==> zgcd (k * m) n = zgcd m n"
  18.103 -  by (simp add: zgcd_def nat_abs_mult_distrib gcd_mult_cancel)
  18.104 -
  18.105 -lemma zgcd_zgcd_zmult:
  18.106 -    "zgcd k m = 1 ==> zgcd n m = 1 ==> zgcd (k * n) m = 1"
  18.107 -  by (simp add: zgcd_zmult_cancel)
  18.108 -
  18.109 -lemma zdvd_iff_zgcd: "0 < m ==> m dvd n \<longleftrightarrow> zgcd n m = m"
  18.110 -  by (metis abs_of_pos dvd_mult_div_cancel zgcd_0 zgcd_commute zgcd_geq_zero zgcd_zdvd2 zgcd_zmult_eq_self)
  18.111 -
  18.112 -
  18.113 -
  18.114 -subsection \<open>Congruences\<close>
  18.115 -
  18.116 -lemma zcong_1 [simp]: "[a = b] (mod 1)"
  18.117 -  by (unfold zcong_def, auto)
  18.118 -
  18.119 -lemma zcong_refl [simp]: "[k = k] (mod m)"
  18.120 -  by (unfold zcong_def, auto)
  18.121 -
  18.122 -lemma zcong_sym: "[a = b] (mod m) = [b = a] (mod m)"
  18.123 -  unfolding zcong_def minus_diff_eq [of a, symmetric] dvd_minus_iff ..
  18.124 -
  18.125 -lemma zcong_zadd:
  18.126 -    "[a = b] (mod m) ==> [c = d] (mod m) ==> [a + c = b + d] (mod m)"
  18.127 -  apply (unfold zcong_def)
  18.128 -  apply (rule_tac s = "(a - b) + (c - d)" in subst)
  18.129 -   apply (rule_tac [2] dvd_add, auto)
  18.130 -  done
  18.131 -
  18.132 -lemma zcong_zdiff:
  18.133 -    "[a = b] (mod m) ==> [c = d] (mod m) ==> [a - c = b - d] (mod m)"
  18.134 -  apply (unfold zcong_def)
  18.135 -  apply (rule_tac s = "(a - b) - (c - d)" in subst)
  18.136 -   apply (rule_tac [2] dvd_diff, auto)
  18.137 -  done
  18.138 -
  18.139 -lemma zcong_trans:
  18.140 -  "[a = b] (mod m) ==> [b = c] (mod m) ==> [a = c] (mod m)"
  18.141 -unfolding zcong_def by (auto elim!: dvdE simp add: algebra_simps)
  18.142 -
  18.143 -lemma zcong_zmult:
  18.144 -    "[a = b] (mod m) ==> [c = d] (mod m) ==> [a * c = b * d] (mod m)"
  18.145 -  apply (rule_tac b = "b * c" in zcong_trans)
  18.146 -   apply (unfold zcong_def)
  18.147 -  apply (metis right_diff_distrib dvd_mult mult.commute)
  18.148 -  apply (metis right_diff_distrib dvd_mult)
  18.149 -  done
  18.150 -
  18.151 -lemma zcong_scalar: "[a = b] (mod m) ==> [a * k = b * k] (mod m)"
  18.152 -  by (rule zcong_zmult, simp_all)
  18.153 -
  18.154 -lemma zcong_scalar2: "[a = b] (mod m) ==> [k * a = k * b] (mod m)"
  18.155 -  by (rule zcong_zmult, simp_all)
  18.156 -
  18.157 -lemma zcong_zmult_self: "[a * m = b * m] (mod m)"
  18.158 -  apply (unfold zcong_def)
  18.159 -  apply (rule dvd_diff, simp_all)
  18.160 -  done
  18.161 -
  18.162 -lemma zcong_square:
  18.163 -   "[| zprime p;  0 < a;  [a * a = 1] (mod p)|]
  18.164 -    ==> [a = 1] (mod p) \<or> [a = p - 1] (mod p)"
  18.165 -  apply (unfold zcong_def)
  18.166 -  apply (rule zprime_zdvd_zmult)
  18.167 -    apply (rule_tac [3] s = "a * a - 1 + p * (1 - a)" in subst)
  18.168 -     prefer 4
  18.169 -     apply (simp add: zdvd_reduce)
  18.170 -    apply (simp_all add: left_diff_distrib mult.commute right_diff_distrib)
  18.171 -  done
  18.172 -
  18.173 -lemma zcong_cancel:
  18.174 -  "0 \<le> m ==>
  18.175 -    zgcd k m = 1 ==> [a * k = b * k] (mod m) = [a = b] (mod m)"
  18.176 -  apply safe
  18.177 -   prefer 2
  18.178 -   apply (blast intro: zcong_scalar)
  18.179 -  apply (case_tac "b < a")
  18.180 -   prefer 2
  18.181 -   apply (subst zcong_sym)
  18.182 -   apply (unfold zcong_def)
  18.183 -   apply (rule_tac [!] zrelprime_zdvd_zmult)
  18.184 -     apply (simp_all add: left_diff_distrib)
  18.185 -  apply (subgoal_tac "m dvd (-(a * k - b * k))")
  18.186 -   apply simp
  18.187 -  apply (subst dvd_minus_iff, assumption)
  18.188 -  done
  18.189 -
  18.190 -lemma zcong_cancel2:
  18.191 -  "0 \<le> m ==>
  18.192 -    zgcd k m = 1 ==> [k * a = k * b] (mod m) = [a = b] (mod m)"
  18.193 -  by (simp add: mult.commute zcong_cancel)
  18.194 -
  18.195 -lemma zcong_zgcd_zmult_zmod:
  18.196 -  "[a = b] (mod m) ==> [a = b] (mod n) ==> zgcd m n = 1
  18.197 -    ==> [a = b] (mod m * n)"
  18.198 -  apply (auto simp add: zcong_def dvd_def)
  18.199 -  apply (subgoal_tac "m dvd n * ka")
  18.200 -   apply (subgoal_tac "m dvd ka")
  18.201 -    apply (case_tac [2] "0 \<le> ka")
  18.202 -  apply (metis dvd_mult_div_cancel dvd_refl dvd_mult_left mult.commute zrelprime_zdvd_zmult)
  18.203 -  apply (metis abs_dvd_iff abs_of_nonneg add_0 zgcd_0_left zgcd_commute zgcd_zadd_zmult zgcd_zdvd_zgcd_zmult zgcd_zmult_distrib2_abs mult_1_right mult.commute)
  18.204 -  apply (metis mult_le_0_iff  zdvd_mono zdvd_mult_cancel dvd_triv_left zero_le_mult_iff order_antisym linorder_linear order_refl mult.commute zrelprime_zdvd_zmult)
  18.205 -  apply (metis dvd_triv_left)
  18.206 -  done
  18.207 -
  18.208 -lemma zcong_zless_imp_eq:
  18.209 -  "0 \<le> a ==>
  18.210 -    a < m ==> 0 \<le> b ==> b < m ==> [a = b] (mod m) ==> a = b"
  18.211 -  apply (unfold zcong_def dvd_def, auto)
  18.212 -  apply (drule_tac f = "\<lambda>z. z mod m" in arg_cong)
  18.213 -  apply (metis diff_add_cancel mod_pos_pos_trivial add_0 add.commute zmod_eq_0_iff mod_add_right_eq)
  18.214 -  done
  18.215 -
  18.216 -lemma zcong_square_zless:
  18.217 -  "zprime p ==> 0 < a ==> a < p ==>
  18.218 -    [a * a = 1] (mod p) ==> a = 1 \<or> a = p - 1"
  18.219 -  apply (cut_tac p = p and a = a in zcong_square)
  18.220 -     apply (simp add: zprime_def)
  18.221 -    apply (auto intro: zcong_zless_imp_eq)
  18.222 -  done
  18.223 -
  18.224 -lemma zcong_not:
  18.225 -    "0 < a ==> a < m ==> 0 < b ==> b < a ==> \<not> [a = b] (mod m)"
  18.226 -  apply (unfold zcong_def)
  18.227 -  apply (rule zdvd_not_zless, auto)
  18.228 -  done
  18.229 -
  18.230 -lemma zcong_zless_0:
  18.231 -    "0 \<le> a ==> a < m ==> [a = 0] (mod m) ==> a = 0"
  18.232 -  apply (unfold zcong_def dvd_def, auto)
  18.233 -  apply (metis div_pos_pos_trivial linorder_not_less nonzero_mult_div_cancel_left)
  18.234 -  done
  18.235 -
  18.236 -lemma zcong_zless_unique:
  18.237 -    "0 < m ==> (\<exists>!b. 0 \<le> b \<and> b < m \<and> [a = b] (mod m))"
  18.238 -  apply auto
  18.239 -   prefer 2 apply (metis zcong_sym zcong_trans zcong_zless_imp_eq)
  18.240 -  apply (unfold zcong_def dvd_def)
  18.241 -  apply (rule_tac x = "a mod m" in exI, auto)
  18.242 -  apply (metis minus_mod_eq_mult_div [symmetric])
  18.243 -  done
  18.244 -
  18.245 -lemma zcong_iff_lin: "([a = b] (mod m)) = (\<exists>k. b = a + m * k)"
  18.246 -  unfolding zcong_def
  18.247 -  apply (auto elim!: dvdE simp add: algebra_simps)
  18.248 -  apply (rule_tac x = "-k" in exI) apply simp
  18.249 -  done
  18.250 -
  18.251 -lemma zgcd_zcong_zgcd:
  18.252 -  "0 < m ==>
  18.253 -    zgcd a m = 1 ==> [a = b] (mod m) ==> zgcd b m = 1"
  18.254 -  by (auto simp add: zcong_iff_lin)
  18.255 -
  18.256 -lemma zcong_zmod_aux:
  18.257 -     "a - b = (m::int) * (a div m - b div m) + (a mod m - b mod m)"
  18.258 -  by(simp add: right_diff_distrib add_diff_eq eq_diff_eq ac_simps)
  18.259 -
  18.260 -lemma zcong_zmod: "[a = b] (mod m) = [a mod m = b mod m] (mod m)"
  18.261 -  apply (unfold zcong_def)
  18.262 -  apply (rule_tac t = "a - b" in ssubst)
  18.263 -  apply (rule_tac m = m in zcong_zmod_aux)
  18.264 -  apply (rule trans)
  18.265 -   apply (rule_tac [2] k = m and m = "a div m - b div m" in zdvd_reduce)
  18.266 -  apply (simp add: add.commute)
  18.267 -  done
  18.268 -
  18.269 -lemma zcong_zmod_eq: "0 < m ==> [a = b] (mod m) = (a mod m = b mod m)"
  18.270 -  apply auto
  18.271 -  apply (metis pos_mod_conj zcong_zless_imp_eq zcong_zmod)
  18.272 -  apply (metis zcong_refl zcong_zmod)
  18.273 -  done
  18.274 -
  18.275 -lemma zcong_zminus [iff]: "[a = b] (mod -m) = [a = b] (mod m)"
  18.276 -  by (auto simp add: zcong_def)
  18.277 -
  18.278 -lemma zcong_zero [iff]: "[a = b] (mod 0) = (a = b)"
  18.279 -  by (auto simp add: zcong_def)
  18.280 -
  18.281 -lemma "[a = b] (mod m) = (a mod m = b mod m)"
  18.282 -  apply (cases "m = 0", simp)
  18.283 -  apply (simp add: linorder_neq_iff)
  18.284 -  apply (erule disjE)  
  18.285 -   prefer 2 apply (simp add: zcong_zmod_eq)
  18.286 -  txt\<open>Remainding case: @{term "m<0"}\<close>
  18.287 -  apply (rule_tac t = m in minus_minus [THEN subst])
  18.288 -  apply (subst zcong_zminus)
  18.289 -  apply (subst zcong_zmod_eq, arith)
  18.290 -  apply (frule neg_mod_bound [of _ a], frule neg_mod_bound [of _ b]) 
  18.291 -  apply (simp add: zmod_zminus2_eq_if del: neg_mod_bound)
  18.292 -  done
  18.293 -
  18.294 -subsection \<open>Modulo\<close>
  18.295 -
  18.296 -lemma zmod_zdvd_zmod:
  18.297 -    "0 < (m::int) ==> m dvd b ==> (a mod b mod m) = (a mod m)"
  18.298 -  by (rule mod_mod_cancel) 
  18.299 -
  18.300 -
  18.301 -subsection \<open>Extended GCD\<close>
  18.302 -
  18.303 -declare xzgcda.simps [simp del]
  18.304 -
  18.305 -lemma xzgcd_correct_aux1:
  18.306 -  "zgcd r' r = k --> 0 < r -->
  18.307 -    (\<exists>sn tn. xzgcda m n r' r s' s t' t = (k, sn, tn))"
  18.308 -  apply (induct m n r' r s' s t' t rule: xzgcda.induct)
  18.309 -  apply (subst zgcd_eq)
  18.310 -  apply (subst xzgcda.simps, auto)
  18.311 -  apply (case_tac "r' mod r = 0")
  18.312 -   prefer 2
  18.313 -   apply (frule_tac a = "r'" in pos_mod_sign, auto)
  18.314 -  apply (rule exI)
  18.315 -  apply (rule exI)
  18.316 -  apply (subst xzgcda.simps, auto)
  18.317 -  done
  18.318 -
  18.319 -lemma xzgcd_correct_aux2:
  18.320 -  "(\<exists>sn tn. xzgcda m n r' r s' s t' t = (k, sn, tn)) --> 0 < r -->
  18.321 -    zgcd r' r = k"
  18.322 -  apply (induct m n r' r s' s t' t rule: xzgcda.induct)
  18.323 -  apply (subst zgcd_eq)
  18.324 -  apply (subst xzgcda.simps)
  18.325 -  apply (auto simp add: linorder_not_le)
  18.326 -  apply (case_tac "r' mod r = 0")
  18.327 -   prefer 2
  18.328 -   apply (frule_tac a = "r'" in pos_mod_sign, auto)
  18.329 -  apply (metis prod.inject xzgcda.simps order_refl)
  18.330 -  done
  18.331 -
  18.332 -lemma xzgcd_correct:
  18.333 -    "0 < n ==> (zgcd m n = k) = (\<exists>s t. xzgcd m n = (k, s, t))"
  18.334 -  apply (unfold xzgcd_def)
  18.335 -  apply (rule iffI)
  18.336 -   apply (rule_tac [2] xzgcd_correct_aux2 [THEN mp, THEN mp])
  18.337 -    apply (rule xzgcd_correct_aux1 [THEN mp, THEN mp], auto)
  18.338 -  done
  18.339 -
  18.340 -
  18.341 -text \<open>\medskip @{term xzgcd} linear\<close>
  18.342 -
  18.343 -lemma xzgcda_linear_aux1:
  18.344 -  "(a - r * b) * m + (c - r * d) * (n::int) =
  18.345 -   (a * m + c * n) - r * (b * m + d * n)"
  18.346 -  by (simp add: left_diff_distrib distrib_left mult.assoc)
  18.347 -
  18.348 -lemma xzgcda_linear_aux2:
  18.349 -  "r' = s' * m + t' * n ==> r = s * m + t * n
  18.350 -    ==> (r' mod r) = (s' - (r' div r) * s) * m + (t' - (r' div r) * t) * (n::int)"
  18.351 -  apply (rule trans)
  18.352 -   apply (rule_tac [2] xzgcda_linear_aux1 [symmetric])
  18.353 -  apply (simp add: eq_diff_eq mult.commute)
  18.354 -  done
  18.355 -
  18.356 -lemma order_le_neq_implies_less: "(x::'a::order) \<le> y ==> x \<noteq> y ==> x < y"
  18.357 -  by (rule iffD2 [OF order_less_le conjI])
  18.358 -
  18.359 -lemma xzgcda_linear [rule_format]:
  18.360 -  "0 < r --> xzgcda m n r' r s' s t' t = (rn, sn, tn) -->
  18.361 -    r' = s' * m + t' * n -->  r = s * m + t * n --> rn = sn * m + tn * n"
  18.362 -  apply (induct m n r' r s' s t' t rule: xzgcda.induct)
  18.363 -  apply (subst xzgcda.simps)
  18.364 -  apply (simp (no_asm))
  18.365 -  apply (rule impI)+
  18.366 -  apply (case_tac "r' mod r = 0")
  18.367 -   apply (simp add: xzgcda.simps, clarify)
  18.368 -  apply (subgoal_tac "0 < r' mod r")
  18.369 -   apply (rule_tac [2] order_le_neq_implies_less)
  18.370 -   apply (rule_tac [2] pos_mod_sign)
  18.371 -    apply (cut_tac m = m and n = n and r' = r' and r = r and s' = s' and
  18.372 -      s = s and t' = t' and t = t in xzgcda_linear_aux2, auto)
  18.373 -  done
  18.374 -
  18.375 -lemma xzgcd_linear:
  18.376 -    "0 < n ==> xzgcd m n = (r, s, t) ==> r = s * m + t * n"
  18.377 -  apply (unfold xzgcd_def)
  18.378 -  apply (erule xzgcda_linear, assumption, auto)
  18.379 -  done
  18.380 -
  18.381 -lemma zgcd_ex_linear:
  18.382 -    "0 < n ==> zgcd m n = k ==> (\<exists>s t. k = s * m + t * n)"
  18.383 -  apply (simp add: xzgcd_correct, safe)
  18.384 -  apply (rule exI)+
  18.385 -  apply (erule xzgcd_linear, auto)
  18.386 -  done
  18.387 -
  18.388 -lemma zcong_lineq_ex:
  18.389 -    "0 < n ==> zgcd a n = 1 ==> \<exists>x. [a * x = 1] (mod n)"
  18.390 -  apply (cut_tac m = a and n = n and k = 1 in zgcd_ex_linear, safe)
  18.391 -  apply (rule_tac x = s in exI)
  18.392 -  apply (rule_tac b = "s * a + t * n" in zcong_trans)
  18.393 -   prefer 2
  18.394 -   apply simp
  18.395 -  apply (unfold zcong_def)
  18.396 -  apply (simp (no_asm) add: mult.commute)
  18.397 -  done
  18.398 -
  18.399 -lemma zcong_lineq_unique:
  18.400 -  "0 < n ==>
  18.401 -    zgcd a n = 1 ==> \<exists>!x. 0 \<le> x \<and> x < n \<and> [a * x = b] (mod n)"
  18.402 -  apply auto
  18.403 -   apply (rule_tac [2] zcong_zless_imp_eq)
  18.404 -       apply (tactic \<open>stac @{context} (@{thm zcong_cancel2} RS sym) 6\<close>)
  18.405 -         apply (rule_tac [8] zcong_trans)
  18.406 -          apply (simp_all (no_asm_simp))
  18.407 -   prefer 2
  18.408 -   apply (simp add: zcong_sym)
  18.409 -  apply (cut_tac a = a and n = n in zcong_lineq_ex, auto)
  18.410 -  apply (rule_tac x = "x * b mod n" in exI, safe)
  18.411 -    apply (simp_all (no_asm_simp))
  18.412 -  apply (metis zcong_scalar zcong_zmod mod_mult_right_eq mult_1 mult.assoc)
  18.413 -  done
  18.414 -
  18.415 -end
    19.1 --- a/src/HOL/Old_Number_Theory/Legacy_GCD.thy	Tue Oct 18 07:04:08 2016 +0200
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,791 +0,0 @@
    19.4 -(*  Title:      HOL/Old_Number_Theory/Legacy_GCD.thy
    19.5 -    Author:     Christophe Tabacznyj and Lawrence C Paulson
    19.6 -    Copyright   1996  University of Cambridge
    19.7 -*)
    19.8 -
    19.9 -section \<open>The Greatest Common Divisor\<close>
   19.10 -
   19.11 -theory Legacy_GCD
   19.12 -imports Main
   19.13 -begin
   19.14 -
   19.15 -text \<open>
   19.16 -  See @{cite davenport92}. \bigskip
   19.17 -\<close>
   19.18 -
   19.19 -subsection \<open>Specification of GCD on nats\<close>
   19.20 -
   19.21 -definition
   19.22 -  is_gcd :: "nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" where \<comment> \<open>@{term gcd} as a relation\<close>
   19.23 -  "is_gcd m n p \<longleftrightarrow> p dvd m \<and> p dvd n \<and>
   19.24 -    (\<forall>d. d dvd m \<longrightarrow> d dvd n \<longrightarrow> d dvd p)"
   19.25 -
   19.26 -text \<open>Uniqueness\<close>
   19.27 -
   19.28 -lemma is_gcd_unique: "is_gcd a b m \<Longrightarrow> is_gcd a b n \<Longrightarrow> m = n"
   19.29 -  by (simp add: is_gcd_def) (blast intro: dvd_antisym)
   19.30 -
   19.31 -text \<open>Connection to divides relation\<close>
   19.32 -
   19.33 -lemma is_gcd_dvd: "is_gcd a b m \<Longrightarrow> k dvd a \<Longrightarrow> k dvd b \<Longrightarrow> k dvd m"
   19.34 -  by (auto simp add: is_gcd_def)
   19.35 -
   19.36 -text \<open>Commutativity\<close>
   19.37 -
   19.38 -lemma is_gcd_commute: "is_gcd m n k = is_gcd n m k"
   19.39 -  by (auto simp add: is_gcd_def)
   19.40 -
   19.41 -
   19.42 -subsection \<open>GCD on nat by Euclid's algorithm\<close>
   19.43 -
   19.44 -fun gcd :: "nat => nat => nat"
   19.45 -  where "gcd m n = (if n = 0 then m else gcd n (m mod n))"
   19.46 -
   19.47 -lemma gcd_induct [case_names "0" rec]:
   19.48 -  fixes m n :: nat
   19.49 -  assumes "\<And>m. P m 0"
   19.50 -    and "\<And>m n. 0 < n \<Longrightarrow> P n (m mod n) \<Longrightarrow> P m n"
   19.51 -  shows "P m n"
   19.52 -proof (induct m n rule: gcd.induct)
   19.53 -  case (1 m n)
   19.54 -  with assms show ?case by (cases "n = 0") simp_all
   19.55 -qed
   19.56 -
   19.57 -lemma gcd_0 [simp, algebra]: "gcd m 0 = m"
   19.58 -  by simp
   19.59 -
   19.60 -lemma gcd_0_left [simp,algebra]: "gcd 0 m = m"
   19.61 -  by simp
   19.62 -
   19.63 -lemma gcd_non_0: "n > 0 \<Longrightarrow> gcd m n = gcd n (m mod n)"
   19.64 -  by simp
   19.65 -
   19.66 -lemma gcd_1 [simp, algebra]: "gcd m (Suc 0) = Suc 0"
   19.67 -  by simp
   19.68 -
   19.69 -lemma nat_gcd_1_right [simp, algebra]: "gcd m 1 = 1"
   19.70 -  unfolding One_nat_def by (rule gcd_1)
   19.71 -
   19.72 -declare gcd.simps [simp del]
   19.73 -
   19.74 -text \<open>
   19.75 -  \medskip @{term "gcd m n"} divides \<open>m\<close> and \<open>n\<close>.  The
   19.76 -  conjunctions don't seem provable separately.
   19.77 -\<close>
   19.78 -
   19.79 -lemma gcd_dvd1 [iff, algebra]: "gcd m n dvd m"
   19.80 -  and gcd_dvd2 [iff, algebra]: "gcd m n dvd n"
   19.81 -  apply (induct m n rule: gcd_induct)
   19.82 -     apply (simp_all add: gcd_non_0)
   19.83 -  apply (blast dest: dvd_mod_imp_dvd)
   19.84 -  done
   19.85 -
   19.86 -text \<open>
   19.87 -  \medskip Maximality: for all @{term m}, @{term n}, @{term k}
   19.88 -  naturals, if @{term k} divides @{term m} and @{term k} divides
   19.89 -  @{term n} then @{term k} divides @{term "gcd m n"}.
   19.90 -\<close>
   19.91 -
   19.92 -lemma gcd_greatest: "k dvd m \<Longrightarrow> k dvd n \<Longrightarrow> k dvd gcd m n"
   19.93 -  by (induct m n rule: gcd_induct) (simp_all add: gcd_non_0 dvd_mod)
   19.94 -
   19.95 -text \<open>
   19.96 -  \medskip Function gcd yields the Greatest Common Divisor.
   19.97 -\<close>
   19.98 -
   19.99 -lemma is_gcd: "is_gcd m n (gcd m n) "
  19.100 -  by (simp add: is_gcd_def gcd_greatest)
  19.101 -
  19.102 -
  19.103 -subsection \<open>Derived laws for GCD\<close>
  19.104 -
  19.105 -lemma gcd_greatest_iff [iff, algebra]: "k dvd gcd m n \<longleftrightarrow> k dvd m \<and> k dvd n"
  19.106 -  by (blast intro!: gcd_greatest intro: dvd_trans)
  19.107 -
  19.108 -lemma gcd_zero[algebra]: "gcd m n = 0 \<longleftrightarrow> m = 0 \<and> n = 0"
  19.109 -  by (simp only: dvd_0_left_iff [symmetric] gcd_greatest_iff)
  19.110 -
  19.111 -lemma gcd_commute: "gcd m n = gcd n m"
  19.112 -  apply (rule is_gcd_unique)
  19.113 -   apply (rule is_gcd)
  19.114 -  apply (subst is_gcd_commute)
  19.115 -  apply (simp add: is_gcd)
  19.116 -  done
  19.117 -
  19.118 -lemma gcd_assoc: "gcd (gcd k m) n = gcd k (gcd m n)"
  19.119 -  apply (rule is_gcd_unique)
  19.120 -   apply (rule is_gcd)
  19.121 -  apply (simp add: is_gcd_def)
  19.122 -  apply (blast intro: dvd_trans)
  19.123 -  done
  19.124 -
  19.125 -lemma gcd_1_left [simp, algebra]: "gcd (Suc 0) m = Suc 0"
  19.126 -  by (simp add: gcd_commute)
  19.127 -
  19.128 -lemma nat_gcd_1_left [simp, algebra]: "gcd 1 m = 1"
  19.129 -  unfolding One_nat_def by (rule gcd_1_left)
  19.130 -
  19.131 -text \<open>
  19.132 -  \medskip Multiplication laws
  19.133 -\<close>
  19.134 -
  19.135 -lemma gcd_mult_distrib2: "k * gcd m n = gcd (k * m) (k * n)"
  19.136 -    \<comment> \<open>@{cite \<open>page 27\<close> davenport92}\<close>
  19.137 -  apply (induct m n rule: gcd_induct)
  19.138 -   apply simp
  19.139 -  apply (case_tac "k = 0")
  19.140 -   apply (simp_all add: gcd_non_0)
  19.141 -  done
  19.142 -
  19.143 -lemma gcd_mult [simp, algebra]: "gcd k (k * n) = k"
  19.144 -  apply (rule gcd_mult_distrib2 [of k 1 n, simplified, symmetric])
  19.145 -  done
  19.146 -
  19.147 -lemma gcd_self [simp, algebra]: "gcd k k = k"
  19.148 -  apply (rule gcd_mult [of k 1, simplified])
  19.149 -  done
  19.150 -
  19.151 -lemma relprime_dvd_mult: "gcd k n = 1 ==> k dvd m * n ==> k dvd m"
  19.152 -  apply (insert gcd_mult_distrib2 [of m k n])
  19.153 -  apply simp
  19.154 -  apply (erule_tac t = m in ssubst)
  19.155 -  apply simp
  19.156 -  done
  19.157 -
  19.158 -lemma relprime_dvd_mult_iff: "gcd k n = 1 ==> (k dvd m * n) = (k dvd m)"
  19.159 -  by (auto intro: relprime_dvd_mult dvd_mult2)
  19.160 -
  19.161 -lemma gcd_mult_cancel: "gcd k n = 1 ==> gcd (k * m) n = gcd m n"
  19.162 -  apply (rule dvd_antisym)
  19.163 -   apply (rule gcd_greatest)
  19.164 -    apply (rule_tac n = k in relprime_dvd_mult)
  19.165 -     apply (simp add: gcd_assoc)
  19.166 -     apply (simp add: gcd_commute)
  19.167 -    apply (simp_all add: mult.commute)
  19.168 -  done
  19.169 -
  19.170 -
  19.171 -text \<open>\medskip Addition laws\<close>
  19.172 -
  19.173 -lemma gcd_add1 [simp, algebra]: "gcd (m + n) n = gcd m n"
  19.174 -  by (cases "n = 0") (auto simp add: gcd_non_0)
  19.175 -
  19.176 -lemma gcd_add2 [simp, algebra]: "gcd m (m + n) = gcd m n"
  19.177 -proof -
  19.178 -  have "gcd m (m + n) = gcd (m + n) m" by (rule gcd_commute)
  19.179 -  also have "... = gcd (n + m) m" by (simp add: add.commute)
  19.180 -  also have "... = gcd n m" by simp
  19.181 -  also have  "... = gcd m n" by (rule gcd_commute)
  19.182 -  finally show ?thesis .
  19.183 -qed
  19.184 -
  19.185 -lemma gcd_add2' [simp, algebra]: "gcd m (n + m) = gcd m n"
  19.186 -  apply (subst add.commute)
  19.187 -  apply (rule gcd_add2)
  19.188 -  done
  19.189 -
  19.190 -lemma gcd_add_mult[algebra]: "gcd m (k * m + n) = gcd m n"
  19.191 -  by (induct k) (simp_all add: add.assoc)
  19.192 -
  19.193 -lemma gcd_dvd_prod: "gcd m n dvd m * n" 
  19.194 -  using mult_dvd_mono [of 1] by auto
  19.195 -
  19.196 -text \<open>
  19.197 -  \medskip Division by gcd yields rrelatively primes.
  19.198 -\<close>
  19.199 -
  19.200 -lemma div_gcd_relprime:
  19.201 -  assumes nz: "a \<noteq> 0 \<or> b \<noteq> 0"
  19.202 -  shows "gcd (a div gcd a b) (b div gcd a b) = 1"
  19.203 -proof -
  19.204 -  let ?g = "gcd a b"
  19.205 -  let ?a' = "a div ?g"
  19.206 -  let ?b' = "b div ?g"
  19.207 -  let ?g' = "gcd ?a' ?b'"
  19.208 -  have dvdg: "?g dvd a" "?g dvd b" by simp_all
  19.209 -  have dvdg': "?g' dvd ?a'" "?g' dvd ?b'" by simp_all
  19.210 -  from dvdg dvdg' obtain ka kb ka' kb' where
  19.211 -      kab: "a = ?g * ka" "b = ?g * kb" "?a' = ?g' * ka'" "?b' = ?g' * kb'"
  19.212 -    unfolding dvd_def by blast
  19.213 -  from this(3-4) [symmetric] have "?g * ?a' = (?g * ?g') * ka'" "?g * ?b' = (?g * ?g') * kb'"
  19.214 -    by (simp_all only: ac_simps mult.left_commute [of _ "gcd a b"])
  19.215 -  then have dvdgg':"?g * ?g' dvd a" "?g* ?g' dvd b"
  19.216 -    by (auto simp add: dvd_mult_div_cancel [OF dvdg(1)]
  19.217 -      dvd_mult_div_cancel [OF dvdg(2)] dvd_def)
  19.218 -  have "?g \<noteq> 0" using nz by (simp add: gcd_zero)
  19.219 -  then have gp: "?g > 0" by simp
  19.220 -  from gcd_greatest [OF dvdgg'] have "?g * ?g' dvd ?g" .
  19.221 -  with dvd_mult_cancel1 [OF gp] show "?g' = 1" by simp
  19.222 -qed
  19.223 -
  19.224 -
  19.225 -lemma gcd_unique: "d dvd a\<and>d dvd b \<and> (\<forall>e. e dvd a \<and> e dvd b \<longrightarrow> e dvd d) \<longleftrightarrow> d = gcd a b"
  19.226 -proof(auto)
  19.227 -  assume H: "d dvd a" "d dvd b" "\<forall>e. e dvd a \<and> e dvd b \<longrightarrow> e dvd d"
  19.228 -  from H(3)[rule_format] gcd_dvd1[of a b] gcd_dvd2[of a b] 
  19.229 -  have th: "gcd a b dvd d" by blast
  19.230 -  from dvd_antisym[OF th gcd_greatest[OF H(1,2)]]  show "d = gcd a b" by blast 
  19.231 -qed
  19.232 -
  19.233 -lemma gcd_eq: assumes H: "\<forall>d. d dvd x \<and> d dvd y \<longleftrightarrow> d dvd u \<and> d dvd v"
  19.234 -  shows "gcd x y = gcd u v"
  19.235 -proof-
  19.236 -  from H have "\<forall>d. d dvd x \<and> d dvd y \<longleftrightarrow> d dvd gcd u v" by simp
  19.237 -  with gcd_unique[of "gcd u v" x y]  show ?thesis by auto
  19.238 -qed
  19.239 -
  19.240 -lemma ind_euclid:
  19.241 -  assumes c: " \<forall>a b. P (a::nat) b \<longleftrightarrow> P b a" and z: "\<forall>a. P a 0"
  19.242 -  and add: "\<forall>a b. P a b \<longrightarrow> P a (a + b)"
  19.243 -  shows "P a b"
  19.244 -proof(induct "a + b" arbitrary: a b rule: less_induct)
  19.245 -  case less
  19.246 -  have "a = b \<or> a < b \<or> b < a" by arith
  19.247 -  moreover {assume eq: "a= b"
  19.248 -    from add[rule_format, OF z[rule_format, of a]] have "P a b" using eq
  19.249 -    by simp}
  19.250 -  moreover
  19.251 -  {assume lt: "a < b"
  19.252 -    hence "a + b - a < a + b \<or> a = 0" by arith
  19.253 -    moreover
  19.254 -    {assume "a =0" with z c have "P a b" by blast }
  19.255 -    moreover
  19.256 -    {assume "a + b - a < a + b"
  19.257 -      also have th0: "a + b - a = a + (b - a)" using lt by arith
  19.258 -      finally have "a + (b - a) < a + b" .
  19.259 -      then have "P a (a + (b - a))" by (rule add[rule_format, OF less])
  19.260 -      then have "P a b" by (simp add: th0[symmetric])}
  19.261 -    ultimately have "P a b" by blast}
  19.262 -  moreover
  19.263 -  {assume lt: "a > b"
  19.264 -    hence "b + a - b < a + b \<or> b = 0" by arith
  19.265 -    moreover
  19.266 -    {assume "b =0" with z c have "P a b" by blast }
  19.267 -    moreover
  19.268 -    {assume "b + a - b < a + b"
  19.269 -      also have th0: "b + a - b = b + (a - b)" using lt by arith
  19.270 -      finally have "b + (a - b) < a + b" .
  19.271 -      then have "P b (b + (a - b))" by (rule add[rule_format, OF less])
  19.272 -      then have "P b a" by (simp add: th0[symmetric])
  19.273 -      hence "P a b" using c by blast }
  19.274 -    ultimately have "P a b" by blast}
  19.275 -ultimately  show "P a b" by blast
  19.276 -qed
  19.277 -
  19.278 -lemma bezout_lemma: 
  19.279 -  assumes ex: "\<exists>(d::nat) x y. d dvd a \<and> d dvd b \<and> (a * x = b * y + d \<or> b * x = a * y + d)"
  19.280 -  shows "\<exists>d x y. d dvd a \<and> d dvd a + b \<and> (a * x = (a + b) * y + d \<or> (a + b) * x = a * y + d)"
  19.281 -using ex
  19.282 -apply clarsimp
  19.283 -apply (rule_tac x="d" in exI, simp)
  19.284 -apply (case_tac "a * x = b * y + d" , simp_all)
  19.285 -apply (rule_tac x="x + y" in exI)
  19.286 -apply (rule_tac x="y" in exI)
  19.287 -apply algebra
  19.288 -apply (rule_tac x="x" in exI)
  19.289 -apply (rule_tac x="x + y" in exI)
  19.290 -apply algebra
  19.291 -done
  19.292 -
  19.293 -lemma bezout_add: "\<exists>(d::nat) x y. d dvd a \<and> d dvd b \<and> (a * x = b * y + d \<or> b * x = a * y + d)"
  19.294 -apply(induct a b rule: ind_euclid)
  19.295 -apply blast
  19.296 -apply clarify
  19.297 -apply (rule_tac x="a" in exI, simp)
  19.298 -apply clarsimp
  19.299 -apply (rule_tac x="d" in exI)
  19.300 -apply (case_tac "a * x = b * y + d", simp_all)
  19.301 -apply (rule_tac x="x+y" in exI)
  19.302 -apply (rule_tac x="y" in exI)
  19.303 -apply algebra
  19.304 -apply (rule_tac x="x" in exI)
  19.305 -apply (rule_tac x="x+y" in exI)
  19.306 -apply algebra
  19.307 -done
  19.308 -
  19.309 -lemma bezout: "\<exists>(d::nat) x y. d dvd a \<and> d dvd b \<and> (a * x - b * y = d \<or> b * x - a * y = d)"
  19.310 -using bezout_add[of a b]
  19.311 -apply clarsimp
  19.312 -apply (rule_tac x="d" in exI, simp)
  19.313 -apply (rule_tac x="x" in exI)
  19.314 -apply (rule_tac x="y" in exI)
  19.315 -apply auto
  19.316 -done
  19.317 -
  19.318 -
  19.319 -text \<open>We can get a stronger version with a nonzeroness assumption.\<close>
  19.320 -lemma divides_le: "m dvd n ==> m <= n \<or> n = (0::nat)" by (auto simp add: dvd_def)
  19.321 -
  19.322 -lemma bezout_add_strong: assumes nz: "a \<noteq> (0::nat)"
  19.323 -  shows "\<exists>d x y. d dvd a \<and> d dvd b \<and> a * x = b * y + d"
  19.324 -proof-
  19.325 -  from nz have ap: "a > 0" by simp
  19.326 - from bezout_add[of a b] 
  19.327 - have "(\<exists>d x y. d dvd a \<and> d dvd b \<and> a * x = b * y + d) \<or> (\<exists>d x y. d dvd a \<and> d dvd b \<and> b * x = a * y + d)" by blast
  19.328 - moreover
  19.329 - {fix d x y assume H: "d dvd a" "d dvd b" "a * x = b * y + d"
  19.330 -   from H have ?thesis by blast }
  19.331 - moreover
  19.332 - {fix d x y assume H: "d dvd a" "d dvd b" "b * x = a * y + d"
  19.333 -   {assume b0: "b = 0" with H  have ?thesis by simp}
  19.334 -   moreover 
  19.335 -   {assume b: "b \<noteq> 0" hence bp: "b > 0" by simp
  19.336 -     from divides_le[OF H(2)] b have "d < b \<or> d = b" using le_less by blast
  19.337 -     moreover
  19.338 -     {assume db: "d=b"
  19.339 -       from nz H db have ?thesis apply simp
  19.340 -         apply (rule exI[where x = b], simp)
  19.341 -         apply (rule exI[where x = b])
  19.342 -        by (rule exI[where x = "a - 1"], simp add: diff_mult_distrib2)}
  19.343 -    moreover
  19.344 -    {assume db: "d < b" 
  19.345 -        {assume "x=0" hence ?thesis using nz H by simp }
  19.346 -        moreover
  19.347 -        {assume x0: "x \<noteq> 0" hence xp: "x > 0" by simp
  19.348 -          
  19.349 -          from db have "d \<le> b - 1" by simp
  19.350 -          hence "d*b \<le> b*(b - 1)" by simp
  19.351 -          with xp mult_mono[of "1" "x" "d*b" "b*(b - 1)"]
  19.352 -          have dble: "d*b \<le> x*b*(b - 1)" using bp by simp
  19.353 -          from H (3) have "a * ((b - 1) * y) + d * (b - 1 + 1) = d + x*b*(b - 1)" by algebra
  19.354 -          hence "a * ((b - 1) * y) = d + x*b*(b - 1) - d*b" using bp by simp
  19.355 -          hence "a * ((b - 1) * y) = d + (x*b*(b - 1) - d*b)" 
  19.356 -            by (simp only: diff_add_assoc[OF dble, of d, symmetric])
  19.357 -          hence "a * ((b - 1) * y) = b*(x*(b - 1) - d) + d"
  19.358 -            by (simp only: diff_mult_distrib2 ac_simps)
  19.359 -          hence ?thesis using H(1,2)
  19.360 -            apply -
  19.361 -            apply (rule exI[where x=d], simp)
  19.362 -            apply (rule exI[where x="(b - 1) * y"])
  19.363 -            by (rule exI[where x="x*(b - 1) - d"], simp)}
  19.364 -        ultimately have ?thesis by blast}
  19.365 -    ultimately have ?thesis by blast}
  19.366 -  ultimately have ?thesis by blast}
  19.367 - ultimately show ?thesis by blast
  19.368 -qed
  19.369 -
  19.370 -
  19.371 -lemma bezout_gcd: "\<exists>x y. a * x - b * y = gcd a b \<or> b * x - a * y = gcd a b"
  19.372 -proof-
  19.373 -  let ?g = "gcd a b"
  19.374 -  from bezout[of a b] obtain d x y where d: "d dvd a" "d dvd b" "a * x - b * y = d \<or> b * x - a * y = d" by blast
  19.375 -  from d(1,2) have "d dvd ?g" by simp
  19.376 -  then obtain k where k: "?g = d*k" unfolding dvd_def by blast
  19.377 -  from d(3) have "(a * x - b * y)*k = d*k \<or> (b * x - a * y)*k = d*k" by blast 
  19.378 -  hence "a * x * k - b * y*k = d*k \<or> b * x * k - a * y*k = d*k" 
  19.379 -    by (algebra add: diff_mult_distrib)
  19.380 -  hence "a * (x * k) - b * (y*k) = ?g \<or> b * (x * k) - a * (y*k) = ?g" 
  19.381 -    by (simp add: k mult.assoc)
  19.382 -  thus ?thesis by blast
  19.383 -qed
  19.384 -
  19.385 -lemma bezout_gcd_strong: assumes a: "a \<noteq> 0" 
  19.386 -  shows "\<exists>x y. a * x = b * y + gcd a b"
  19.387 -proof-
  19.388 -  let ?g = "gcd a b"
  19.389 -  from bezout_add_strong[OF a, of b]
  19.390 -  obtain d x y where d: "d dvd a" "d dvd b" "a * x = b * y + d" by blast
  19.391 -  from d(1,2) have "d dvd ?g" by simp
  19.392 -  then obtain k where k: "?g = d*k" unfolding dvd_def by blast
  19.393 -  from d(3) have "a * x * k = (b * y + d) *k " by algebra
  19.394 -  hence "a * (x * k) = b * (y*k) + ?g" by (algebra add: k)
  19.395 -  thus ?thesis by blast
  19.396 -qed
  19.397 -
  19.398 -lemma gcd_mult_distrib: "gcd(a * c) (b * c) = c * gcd a b"
  19.399 -by(simp add: gcd_mult_distrib2 mult.commute)
  19.400 -
  19.401 -lemma gcd_bezout: "(\<exists>x y. a * x - b * y = d \<or> b * x - a * y = d) \<longleftrightarrow> gcd a b dvd d"
  19.402 -  (is "?lhs \<longleftrightarrow> ?rhs")
  19.403 -proof-
  19.404 -  let ?g = "gcd a b"
  19.405 -  {assume H: ?rhs then obtain k where k: "d = ?g*k" unfolding dvd_def by blast
  19.406 -    from bezout_gcd[of a b] obtain x y where xy: "a * x - b * y = ?g \<or> b * x - a * y = ?g"
  19.407 -      by blast
  19.408 -    hence "(a * x - b * y)*k = ?g*k \<or> (b * x - a * y)*k = ?g*k" by auto
  19.409 -    hence "a * x*k - b * y*k = ?g*k \<or> b * x * k - a * y*k = ?g*k" 
  19.410 -      by (simp only: diff_mult_distrib)
  19.411 -    hence "a * (x*k) - b * (y*k) = d \<or> b * (x * k) - a * (y*k) = d"
  19.412 -      by (simp add: k[symmetric] mult.assoc)
  19.413 -    hence ?lhs by blast}
  19.414 -  moreover
  19.415 -  {fix x y assume H: "a * x - b * y = d \<or> b * x - a * y = d"
  19.416 -    have dv: "?g dvd a*x" "?g dvd b * y" "?g dvd b*x" "?g dvd a * y"
  19.417 -      using dvd_mult2[OF gcd_dvd1[of a b]] dvd_mult2[OF gcd_dvd2[of a b]] by simp_all
  19.418 -    from dvd_diff_nat[OF dv(1,2)] dvd_diff_nat[OF dv(3,4)] H
  19.419 -    have ?rhs by auto}
  19.420 -  ultimately show ?thesis by blast
  19.421 -qed
  19.422 -
  19.423 -lemma gcd_bezout_sum: assumes H:"a * x + b * y = d" shows "gcd a b dvd d"
  19.424 -proof-
  19.425 -  let ?g = "gcd a b"
  19.426 -    have dv: "?g dvd a*x" "?g dvd b * y" 
  19.427 -      using dvd_mult2[OF gcd_dvd1[of a b]] dvd_mult2[OF gcd_dvd2[of a b]] by simp_all
  19.428 -    from dvd_add[OF dv] H
  19.429 -    show ?thesis by auto
  19.430 -qed
  19.431 -
  19.432 -lemma gcd_mult': "gcd b (a * b) = b"
  19.433 -by (simp add: mult.commute[of a b]) 
  19.434 -
  19.435 -lemma gcd_add: "gcd(a + b) b = gcd a b" 
  19.436 -  "gcd(b + a) b = gcd a b" "gcd a (a + b) = gcd a b" "gcd a (b + a) = gcd a b"
  19.437 -by (simp_all add: gcd_commute)
  19.438 -
  19.439 -lemma gcd_sub: "b <= a ==> gcd(a - b) b = gcd a b" "a <= b ==> gcd a (b - a) = gcd a b"
  19.440 -proof-
  19.441 -  {fix a b assume H: "b \<le> (a::nat)"
  19.442 -    hence th: "a - b + b = a" by arith
  19.443 -    from gcd_add(1)[of "a - b" b] th  have "gcd(a - b) b = gcd a b" by simp}
  19.444 -  note th = this
  19.445 -{
  19.446 -  assume ab: "b \<le> a"
  19.447 -  from th[OF ab] show "gcd (a - b)  b = gcd a b" by blast
  19.448 -next
  19.449 -  assume ab: "a \<le> b"
  19.450 -  from th[OF ab] show "gcd a (b - a) = gcd a b" 
  19.451 -    by (simp add: gcd_commute)}
  19.452 -qed
  19.453 -
  19.454 -
  19.455 -subsection \<open>LCM defined by GCD\<close>
  19.456 -
  19.457 -
  19.458 -definition
  19.459 -  lcm :: "nat \<Rightarrow> nat \<Rightarrow> nat"
  19.460 -where
  19.461 -  lcm_def: "lcm m n = m * n div gcd m n"
  19.462 -
  19.463 -lemma prod_gcd_lcm:
  19.464 -  "m * n = gcd m n * lcm m n"
  19.465 -  unfolding lcm_def by (simp add: dvd_mult_div_cancel [OF gcd_dvd_prod])
  19.466 -
  19.467 -lemma lcm_0 [simp]: "lcm m 0 = 0"
  19.468 -  unfolding lcm_def by simp
  19.469 -
  19.470 -lemma lcm_1 [simp]: "lcm m 1 = m"
  19.471 -  unfolding lcm_def by simp
  19.472 -
  19.473 -lemma lcm_0_left [simp]: "lcm 0 n = 0"
  19.474 -  unfolding lcm_def by simp
  19.475 -
  19.476 -lemma lcm_1_left [simp]: "lcm 1 m = m"
  19.477 -  unfolding lcm_def by simp
  19.478 -
  19.479 -lemma dvd_pos:
  19.480 -  fixes n m :: nat
  19.481 -  assumes "n > 0" and "m dvd n"
  19.482 -  shows "m > 0"
  19.483 -using assms by (cases m) auto
  19.484 -
  19.485 -lemma lcm_least:
  19.486 -  assumes "m dvd k" and "n dvd k"
  19.487 -  shows "lcm m n dvd k"
  19.488 -proof (cases k)
  19.489 -  case 0 then show ?thesis by auto
  19.490 -next
  19.491 -  case (Suc _) then have pos_k: "k > 0" by auto
  19.492 -  from assms dvd_pos [OF this] have pos_mn: "m > 0" "n > 0" by auto
  19.493 -  with gcd_zero [of m n] have pos_gcd: "gcd m n > 0" by simp
  19.494 -  from assms obtain p where k_m: "k = m * p" using dvd_def by blast
  19.495 -  from assms obtain q where k_n: "k = n * q" using dvd_def by blast
  19.496 -  from pos_k k_m have pos_p: "p > 0" by auto
  19.497 -  from pos_k k_n have pos_q: "q > 0" by auto
  19.498 -  have "k * k * gcd q p = k * gcd (k * q) (k * p)"
  19.499 -    by (simp add: ac_simps gcd_mult_distrib2)
  19.500 -  also have "\<dots> = k * gcd (m * p * q) (n * q * p)"
  19.501 -    by (simp add: k_m [symmetric] k_n [symmetric])
  19.502 -  also have "\<dots> = k * p * q * gcd m n"
  19.503 -    by (simp add: ac_simps gcd_mult_distrib2)
  19.504 -  finally have "(m * p) * (n * q) * gcd q p = k * p * q * gcd m n"
  19.505 -    by (simp only: k_m [symmetric] k_n [symmetric])
  19.506 -  then have "p * q * m * n * gcd q p = p * q * k * gcd m n"
  19.507 -    by (simp add: ac_simps)
  19.508 -  with pos_p pos_q have "m * n * gcd q p = k * gcd m n"
  19.509 -    by simp
  19.510 -  with prod_gcd_lcm [of m n]
  19.511 -  have "lcm m n * gcd q p * gcd m n = k * gcd m n"
  19.512 -    by (simp add: ac_simps)
  19.513 -  with pos_gcd have "lcm m n * gcd q p = k" by simp
  19.514 -  then show ?thesis using dvd_def by auto
  19.515 -qed
  19.516 -
  19.517 -lemma lcm_dvd1 [iff]:
  19.518 -  "m dvd lcm m n"
  19.519 -proof (cases m)
  19.520 -  case 0 then show ?thesis by simp
  19.521 -next
  19.522 -  case (Suc _)
  19.523 -  then have mpos: "m > 0" by simp
  19.524 -  show ?thesis
  19.525 -  proof (cases n)
  19.526 -    case 0 then show ?thesis by simp
  19.527 -  next
  19.528 -    case (Suc _)
  19.529 -    then have npos: "n > 0" by simp
  19.530 -    have "gcd m n dvd n" by simp
  19.531 -    then obtain k where "n = gcd m n * k" using dvd_def by auto
  19.532 -    then have "m * n div gcd m n = m * (gcd m n * k) div gcd m n" by (simp add: ac_simps)
  19.533 -    also have "\<dots> = m * k" using mpos npos gcd_zero by simp
  19.534 -    finally show ?thesis by (simp add: lcm_def)
  19.535 -  qed
  19.536 -qed
  19.537 -
  19.538 -lemma lcm_dvd2 [iff]: 
  19.539 -  "n dvd lcm m n"
  19.540 -proof (cases n)
  19.541 -  case 0 then show ?thesis by simp
  19.542 -next
  19.543 -  case (Suc _)
  19.544 -  then have npos: "n > 0" by simp
  19.545 -  show ?thesis
  19.546 -  proof (cases m)
  19.547 -    case 0 then show ?thesis by simp
  19.548 -  next
  19.549 -    case (Suc _)
  19.550 -    then have mpos: "m > 0" by simp
  19.551 -    have "gcd m n dvd m" by simp
  19.552 -    then obtain k where "m = gcd m n * k" using dvd_def by auto
  19.553 -    then have "m * n div gcd m n = (gcd m n * k) * n div gcd m n" by (simp add: ac_simps)
  19.554 -    also have "\<dots> = n * k" using mpos npos gcd_zero by simp
  19.555 -    finally show ?thesis by (simp add: lcm_def)
  19.556 -  qed
  19.557 -qed
  19.558 -
  19.559 -lemma gcd_add1_eq: "gcd (m + k) k = gcd (m + k) m"
  19.560 -  by (simp add: gcd_commute)
  19.561 -
  19.562 -lemma gcd_diff2: "m \<le> n ==> gcd n (n - m) = gcd n m"
  19.563 -  apply (subgoal_tac "n = m + (n - m)")
  19.564 -  apply (erule ssubst, rule gcd_add1_eq, simp)  
  19.565 -  done
  19.566 -
  19.567 -
  19.568 -subsection \<open>GCD and LCM on integers\<close>
  19.569 -
  19.570 -definition
  19.571 -  zgcd :: "int \<Rightarrow> int \<Rightarrow> int" where
  19.572 -  "zgcd i j = int (gcd (nat \<bar>i\<bar>) (nat \<bar>j\<bar>))"
  19.573 -
  19.574 -lemma zgcd_zdvd1 [iff, algebra]: "zgcd i j dvd i"
  19.575 -by (simp add: zgcd_def int_dvd_iff)
  19.576 -
  19.577 -lemma zgcd_zdvd2 [iff, algebra]: "zgcd i j dvd j"
  19.578 -by (simp add: zgcd_def int_dvd_iff)
  19.579 -
  19.580 -lemma zgcd_pos: "zgcd i j \<ge> 0"
  19.581 -by (simp add: zgcd_def)
  19.582 -
  19.583 -lemma zgcd0 [simp,algebra]: "(zgcd i j = 0) = (i = 0 \<and> j = 0)"
  19.584 -by (simp add: zgcd_def gcd_zero)
  19.585 -
  19.586 -lemma zgcd_commute: "zgcd i j = zgcd j i"
  19.587 -unfolding zgcd_def by (simp add: gcd_commute)
  19.588 -
  19.589 -lemma zgcd_zminus [simp, algebra]: "zgcd (- i) j = zgcd i j"
  19.590 -unfolding zgcd_def by simp
  19.591 -
  19.592 -lemma zgcd_zminus2 [simp, algebra]: "zgcd i (- j) = zgcd i j"
  19.593 -unfolding zgcd_def by simp
  19.594 -
  19.595 -  (* should be solved by algebra*)
  19.596 -lemma zrelprime_dvd_mult: "zgcd i j = 1 \<Longrightarrow> i dvd k * j \<Longrightarrow> i dvd k"
  19.597 -  unfolding zgcd_def
  19.598 -proof -
  19.599 -  assume "int (gcd (nat \<bar>i\<bar>) (nat \<bar>j\<bar>)) = 1" "i dvd k * j"
  19.600 -  then have g: "gcd (nat \<bar>i\<bar>) (nat \<bar>j\<bar>) = 1" by simp
  19.601 -  from \<open>i dvd k * j\<close> obtain h where h: "k*j = i*h" unfolding dvd_def by blast
  19.602 -  have th: "nat \<bar>i\<bar> dvd nat \<bar>k\<bar> * nat \<bar>j\<bar>"
  19.603 -    unfolding dvd_def
  19.604 -    by (rule_tac x= "nat \<bar>h\<bar>" in exI, simp add: h nat_abs_mult_distrib [symmetric])
  19.605 -  from relprime_dvd_mult [OF g th] obtain h' where h': "nat \<bar>k\<bar> = nat \<bar>i\<bar> * h'"
  19.606 -    unfolding dvd_def by blast
  19.607 -  from h' have "int (nat \<bar>k\<bar>) = int (nat \<bar>i\<bar> * h')" by simp
  19.608 -  then have "\<bar>k\<bar> = \<bar>i\<bar> * int h'" by (simp add: of_nat_mult)
  19.609 -  then show ?thesis
  19.610 -    apply (subst abs_dvd_iff [symmetric])
  19.611 -    apply (subst dvd_abs_iff [symmetric])
  19.612 -    apply (unfold dvd_def)
  19.613 -    apply (rule_tac x = "int h'" in exI, simp)
  19.614 -    done
  19.615 -qed
  19.616 -
  19.617 -lemma int_nat_abs: "int (nat \<bar>x\<bar>) = \<bar>x\<bar>" by arith
  19.618 -
  19.619 -lemma zgcd_greatest:
  19.620 -  assumes "k dvd m" and "k dvd n"
  19.621 -  shows "k dvd zgcd m n"
  19.622 -proof -
  19.623 -  let ?k' = "nat \<bar>k\<bar>"
  19.624 -  let ?m' = "nat \<bar>m\<bar>"
  19.625 -  let ?n' = "nat \<bar>n\<bar>"
  19.626 -  from \<open>k dvd m\<close> and \<open>k dvd n\<close> have dvd': "?k' dvd ?m'" "?k' dvd ?n'"
  19.627 -    unfolding zdvd_int by (simp_all only: int_nat_abs abs_dvd_iff dvd_abs_iff)
  19.628 -  from gcd_greatest [OF dvd'] have "int (nat \<bar>k\<bar>) dvd zgcd m n"
  19.629 -    unfolding zgcd_def by (simp only: zdvd_int)
  19.630 -  then have "\<bar>k\<bar> dvd zgcd m n" by (simp only: int_nat_abs)
  19.631 -  then show "k dvd zgcd m n" by simp
  19.632 -qed
  19.633 -
  19.634 -lemma div_zgcd_relprime:
  19.635 -  assumes nz: "a \<noteq> 0 \<or> b \<noteq> 0"
  19.636 -  shows "zgcd (a div (zgcd a b)) (b div (zgcd a b)) = 1"
  19.637 -proof -
  19.638 -  from nz have nz': "nat \<bar>a\<bar> \<noteq> 0 \<or> nat \<bar>b\<bar> \<noteq> 0" by arith 
  19.639 -  let ?g = "zgcd a b"
  19.640 -  let ?a' = "a div ?g"
  19.641 -  let ?b' = "b div ?g"
  19.642 -  let ?g' = "zgcd ?a' ?b'"
  19.643 -  have dvdg: "?g dvd a" "?g dvd b" by simp_all
  19.644 -  have dvdg': "?g' dvd ?a'" "?g' dvd ?b'" by simp_all
  19.645 -  from dvdg dvdg' obtain ka kb ka' kb' where
  19.646 -   kab: "a = ?g*ka" "b = ?g*kb" "?a' = ?g'*ka'" "?b' = ?g' * kb'"
  19.647 -    unfolding dvd_def by blast
  19.648 -  from this(3-4) [symmetric] have "?g* ?a' = (?g * ?g') * ka'" "?g* ?b' = (?g * ?g') * kb'"
  19.649 -    by (simp_all only: ac_simps mult.left_commute [of _ "zgcd a b"])
  19.650 -  then have dvdgg':"?g * ?g' dvd a" "?g* ?g' dvd b"
  19.651 -    by (auto simp add: dvd_mult_div_cancel [OF dvdg(1)]
  19.652 -      dvd_mult_div_cancel [OF dvdg(2)] dvd_def)
  19.653 -  have "?g \<noteq> 0" using nz by simp
  19.654 -  then have gp: "?g \<noteq> 0" using zgcd_pos[where i="a" and j="b"] by arith
  19.655 -  from zgcd_greatest [OF dvdgg'] have "?g * ?g' dvd ?g" .
  19.656 -  with zdvd_mult_cancel1 [OF gp] have "\<bar>?g'\<bar> = 1" by simp
  19.657 -  with zgcd_pos show "?g' = 1" by simp
  19.658 -qed
  19.659 -
  19.660 -lemma zgcd_0 [simp, algebra]: "zgcd m 0 = \<bar>m\<bar>"
  19.661 -  by (simp add: zgcd_def abs_if)
  19.662 -
  19.663 -lemma zgcd_0_left [simp, algebra]: "zgcd 0 m = \<bar>m\<bar>"
  19.664 -  by (simp add: zgcd_def abs_if)
  19.665 -
  19.666 -lemma zgcd_non_0: "0 < n ==> zgcd m n = zgcd n (m mod n)"
  19.667 -  apply (frule_tac b = n and a = m in pos_mod_sign)
  19.668 -  apply (simp del: pos_mod_sign add: zgcd_def abs_if nat_mod_distrib)
  19.669 -  apply (auto simp add: gcd_non_0 nat_mod_distrib [symmetric] zmod_zminus1_eq_if)
  19.670 -  apply (frule_tac a = m in pos_mod_bound)
  19.671 -  apply (simp del: pos_mod_bound add: algebra_simps nat_diff_distrib gcd_diff2 nat_le_eq_zle)
  19.672 -  apply (metis dual_order.strict_implies_order gcd.simps gcd_0_left gcd_diff2 mod_by_0 nat_mono)
  19.673 -  done
  19.674 -
  19.675 -lemma zgcd_eq: "zgcd m n = zgcd n (m mod n)"
  19.676 -  apply (cases "n = 0", simp)
  19.677 -  apply (auto simp add: linorder_neq_iff zgcd_non_0)
  19.678 -  apply (cut_tac m = "-m" and n = "-n" in zgcd_non_0, auto)
  19.679 -  done
  19.680 -
  19.681 -lemma zgcd_1 [simp, algebra]: "zgcd m 1 = 1"
  19.682 -  by (simp add: zgcd_def abs_if)
  19.683 -
  19.684 -lemma zgcd_0_1_iff [simp, algebra]: "zgcd 0 m = 1 \<longleftrightarrow> \<bar>m\<bar> = 1"
  19.685 -  by (simp add: zgcd_def abs_if)
  19.686 -
  19.687 -lemma zgcd_greatest_iff[algebra]: "k dvd zgcd m n = (k dvd m \<and> k dvd n)"
  19.688 -  by (simp add: zgcd_def abs_if int_dvd_iff dvd_int_iff nat_dvd_iff)
  19.689 -
  19.690 -lemma zgcd_1_left [simp, algebra]: "zgcd 1 m = 1"
  19.691 -  by (simp add: zgcd_def)
  19.692 -
  19.693 -lemma zgcd_assoc: "zgcd (zgcd k m) n = zgcd k (zgcd m n)"
  19.694 -  by (simp add: zgcd_def gcd_assoc)
  19.695 -
  19.696 -lemma zgcd_left_commute: "zgcd k (zgcd m n) = zgcd m (zgcd k n)"
  19.697 -  apply (rule zgcd_commute [THEN trans])
  19.698 -  apply (rule zgcd_assoc [THEN trans])
  19.699 -  apply (rule zgcd_commute [THEN arg_cong])
  19.700 -  done
  19.701 -
  19.702 -lemmas zgcd_ac = zgcd_assoc zgcd_commute zgcd_left_commute
  19.703 -  \<comment> \<open>addition is an AC-operator\<close>
  19.704 -
  19.705 -lemma zgcd_zmult_distrib2: "0 \<le> k ==> k * zgcd m n = zgcd (k * m) (k * n)"
  19.706 -  by (simp del: minus_mult_right [symmetric]
  19.707 -      add: minus_mult_right nat_mult_distrib zgcd_def abs_if
  19.708 -          mult_less_0_iff gcd_mult_distrib2 [symmetric] of_nat_mult)
  19.709 -
  19.710 -lemma zgcd_zmult_distrib2_abs: "zgcd (k * m) (k * n) = \<bar>k\<bar> * zgcd m n"
  19.711 -  by (simp add: abs_if zgcd_zmult_distrib2)
  19.712 -
  19.713 -lemma zgcd_self [simp]: "0 \<le> m ==> zgcd m m = m"
  19.714 -  by (cut_tac k = m and m = 1 and n = 1 in zgcd_zmult_distrib2, simp_all)
  19.715 -
  19.716 -lemma zgcd_zmult_eq_self [simp]: "0 \<le> k ==> zgcd k (k * n) = k"
  19.717 -  by (cut_tac k = k and m = 1 and n = n in zgcd_zmult_distrib2, simp_all)
  19.718 -
  19.719 -lemma zgcd_zmult_eq_self2 [simp]: "0 \<le> k ==> zgcd (k * n) k = k"
  19.720 -  by (cut_tac k = k and m = n and n = 1 in zgcd_zmult_distrib2, simp_all)
  19.721 -
  19.722 -
  19.723 -definition "zlcm i j = int (lcm (nat \<bar>i\<bar>) (nat \<bar>j\<bar>))"
  19.724 -
  19.725 -lemma dvd_zlcm_self1[simp, algebra]: "i dvd zlcm i j"
  19.726 -by(simp add:zlcm_def dvd_int_iff)
  19.727 -
  19.728 -lemma dvd_zlcm_self2[simp, algebra]: "j dvd zlcm i j"
  19.729 -by(simp add:zlcm_def dvd_int_iff)
  19.730 -
  19.731 -
  19.732 -lemma dvd_imp_dvd_zlcm1:
  19.733 -  assumes "k dvd i" shows "k dvd (zlcm i j)"
  19.734 -proof -
  19.735 -  have "nat \<bar>k\<bar> dvd nat \<bar>i\<bar>" using \<open>k dvd i\<close>
  19.736 -    by(simp add:int_dvd_iff[symmetric] dvd_int_iff[symmetric])
  19.737 -  thus ?thesis by(simp add:zlcm_def dvd_int_iff)(blast intro: dvd_trans)
  19.738 -qed
  19.739 -
  19.740 -lemma dvd_imp_dvd_zlcm2:
  19.741 -  assumes "k dvd j" shows "k dvd (zlcm i j)"
  19.742 -proof -
  19.743 -  have "nat \<bar>k\<bar> dvd nat \<bar>j\<bar>" using \<open>k dvd j\<close>
  19.744 -    by(simp add:int_dvd_iff[symmetric] dvd_int_iff[symmetric])
  19.745 -  thus ?thesis by(simp add:zlcm_def dvd_int_iff)(blast intro: dvd_trans)
  19.746 -qed
  19.747 -
  19.748 -
  19.749 -lemma zdvd_self_abs1: "(d::int) dvd \<bar>d\<bar>"
  19.750 -by (case_tac "d <0", simp_all)
  19.751 -
  19.752 -lemma zdvd_self_abs2: "\<bar>d::int\<bar> dvd d"
  19.753 -by (case_tac "d<0", simp_all)
  19.754 -
  19.755 -(* lcm a b is positive for positive a and b *)
  19.756 -
  19.757 -lemma lcm_pos: 
  19.758 -  assumes mpos: "m > 0"
  19.759 -    and npos: "n>0"
  19.760 -  shows "lcm m n > 0"
  19.761 -proof (rule ccontr, simp add: lcm_def gcd_zero)
  19.762 -  assume h:"m*n div gcd m n = 0"
  19.763 -  from mpos npos have "gcd m n \<noteq> 0" using gcd_zero by simp
  19.764 -  hence gcdp: "gcd m n > 0" by simp
  19.765 -  with h
  19.766 -  have "m*n < gcd m n"
  19.767 -    by (cases "m * n < gcd m n") (auto simp add: div_if[OF gcdp, where m="m*n"])
  19.768 -  moreover 
  19.769 -  have "gcd m n dvd m" by simp
  19.770 -  with mpos dvd_imp_le have t1:"gcd m n \<le> m" by simp
  19.771 -  with npos have t1:"gcd m n *n \<le> m*n" by simp
  19.772 -  have "gcd m n \<le> gcd m n*n" using npos by simp
  19.773 -  with t1 have "gcd m n \<le> m*n" by arith
  19.774 -  ultimately show "False" by simp
  19.775 -qed
  19.776 -
  19.777 -lemma zlcm_pos: 
  19.778 -  assumes anz: "a \<noteq> 0"
  19.779 -  and bnz: "b \<noteq> 0" 
  19.780 -  shows "0 < zlcm a b"
  19.781 -proof-
  19.782 -  let ?na = "nat \<bar>a\<bar>"
  19.783 -  let ?nb = "nat \<bar>b\<bar>"
  19.784 -  have nap: "?na >0" using anz by simp
  19.785 -  have nbp: "?nb >0" using bnz by simp
  19.786 -  have "0 < lcm ?na ?nb" by (rule lcm_pos[OF nap nbp])
  19.787 -  thus ?thesis by (simp add: zlcm_def)
  19.788 -qed
  19.789 -
  19.790 -lemma zgcd_code [code]:
  19.791 -  "zgcd k l = \<bar>if l = 0 then k else zgcd l (\<bar>k\<bar> mod \<bar>l\<bar>)\<bar>"
  19.792 -  by (simp add: zgcd_def gcd.simps [of "nat \<bar>k\<bar>"] nat_mod_distrib)
  19.793 -
  19.794 -end
    20.1 --- a/src/HOL/Old_Number_Theory/Pocklington.thy	Tue Oct 18 07:04:08 2016 +0200
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,1263 +0,0 @@
    20.4 -(*  Title:      HOL/Old_Number_Theory/Pocklington.thy
    20.5 -    Author:     Amine Chaieb
    20.6 -*)
    20.7 -
    20.8 -section \<open>Pocklington's Theorem for Primes\<close>
    20.9 -
   20.10 -theory Pocklington
   20.11 -imports Primes
   20.12 -begin
   20.13 -
   20.14 -definition modeq:: "nat => nat => nat => bool"    ("(1[_ = _] '(mod _'))")
   20.15 -  where "[a = b] (mod p) == ((a mod p) = (b mod p))"
   20.16 -
   20.17 -definition modneq:: "nat => nat => nat => bool"    ("(1[_ \<noteq> _] '(mod _'))")
   20.18 -  where "[a \<noteq> b] (mod p) == ((a mod p) \<noteq> (b mod p))"
   20.19 -
   20.20 -lemma modeq_trans:
   20.21 -  "\<lbrakk> [a = b] (mod p); [b = c] (mod p) \<rbrakk> \<Longrightarrow> [a = c] (mod p)"
   20.22 -  by (simp add:modeq_def)
   20.23 -
   20.24 -lemma modeq_sym[sym]:
   20.25 -  "[a = b] (mod p) \<Longrightarrow> [b = a] (mod p)"
   20.26 -  unfolding modeq_def by simp
   20.27 -
   20.28 -lemma modneq_sym[sym]:
   20.29 -  "[a \<noteq> b] (mod p) \<Longrightarrow> [b \<noteq> a] (mod p)"
   20.30 -  by (simp add: modneq_def)
   20.31 -
   20.32 -lemma nat_mod_lemma: assumes xyn: "[x = y] (mod n)" and xy:"y \<le> x"
   20.33 -  shows "\<exists>q. x = y + n * q"
   20.34 -using xyn xy unfolding modeq_def using nat_mod_eq_lemma by blast
   20.35 -
   20.36 -lemma nat_mod[algebra]: "[x = y] (mod n) \<longleftrightarrow> (\<exists>q1 q2. x + n * q1 = y + n * q2)"
   20.37 -unfolding modeq_def nat_mod_eq_iff ..
   20.38 -
   20.39 -(* Lemmas about previously defined terms.                                    *)
   20.40 -
   20.41 -lemma prime: "prime p \<longleftrightarrow> p \<noteq> 0 \<and> p\<noteq>1 \<and> (\<forall>m. 0 < m \<and> m < p \<longrightarrow> coprime p m)"
   20.42 -  (is "?lhs \<longleftrightarrow> ?rhs")
   20.43 -proof-
   20.44 -  {assume "p=0 \<or> p=1" hence ?thesis using prime_0 prime_1 by (cases "p=0", simp_all)}
   20.45 -  moreover
   20.46 -  {assume p0: "p\<noteq>0" "p\<noteq>1"
   20.47 -    {assume H: "?lhs"
   20.48 -      {fix m assume m: "m > 0" "m < p"
   20.49 -        {assume "m=1" hence "coprime p m" by simp}
   20.50 -        moreover
   20.51 -        {assume "p dvd m" hence "p \<le> m" using dvd_imp_le m by blast with m(2)
   20.52 -          have "coprime p m" by simp}
   20.53 -        ultimately have "coprime p m" using prime_coprime[OF H, of m] by blast}
   20.54 -      hence ?rhs using p0 by auto}
   20.55 -    moreover
   20.56 -    { assume H: "\<forall>m. 0 < m \<and> m < p \<longrightarrow> coprime p m"
   20.57 -      from prime_factor[OF p0(2)] obtain q where q: "prime q" "q dvd p" by blast
   20.58 -      from prime_ge_2[OF q(1)] have q0: "q > 0" by arith
   20.59 -      from dvd_imp_le[OF q(2)] p0 have qp: "q \<le> p" by arith
   20.60 -      {assume "q = p" hence ?lhs using q(1) by blast}
   20.61 -      moreover
   20.62 -      {assume "q\<noteq>p" with qp have qplt: "q < p" by arith
   20.63 -        from H[rule_format, of q] qplt q0 have "coprime p q" by arith
   20.64 -        with coprime_prime[of p q q] q have False by simp hence ?lhs by blast}
   20.65 -      ultimately have ?lhs by blast}
   20.66 -    ultimately have ?thesis by blast}
   20.67 -  ultimately show ?thesis  by (cases"p=0 \<or> p=1", auto)
   20.68 -qed
   20.69 -
   20.70 -lemma finite_number_segment: "card { m. 0 < m \<and> m < n } = n - 1"
   20.71 -proof-
   20.72 -  have "{ m. 0 < m \<and> m < n } = {1..<n}" by auto
   20.73 -  thus ?thesis by simp
   20.74 -qed
   20.75 -
   20.76 -lemma coprime_mod: assumes n: "n \<noteq> 0" shows "coprime (a mod n) n \<longleftrightarrow> coprime a n"
   20.77 -  using n dvd_mod_iff[of _ n a] by (auto simp add: coprime)
   20.78 -
   20.79 -(* Congruences.                                                              *)
   20.80 -
   20.81 -lemma cong_mod_01[simp,presburger]:
   20.82 -  "[x = y] (mod 0) \<longleftrightarrow> x = y" "[x = y] (mod 1)" "[x = 0] (mod n) \<longleftrightarrow> n dvd x"
   20.83 -  by (simp_all add: modeq_def, presburger)
   20.84 -
   20.85 -lemma cong_sub_cases:
   20.86 -  "[x = y] (mod n) \<longleftrightarrow> (if x <= y then [y - x = 0] (mod n) else [x - y = 0] (mod n))"
   20.87 -apply (auto simp add: nat_mod)
   20.88 -apply (rule_tac x="q2" in exI)
   20.89 -apply (rule_tac x="q1" in exI, simp)
   20.90 -apply (rule_tac x="q2" in exI)
   20.91 -apply (rule_tac x="q1" in exI, simp)
   20.92 -apply (rule_tac x="q1" in exI)
   20.93 -apply (rule_tac x="q2" in exI, simp)
   20.94 -apply (rule_tac x="q1" in exI)
   20.95 -apply (rule_tac x="q2" in exI, simp)
   20.96 -done
   20.97 -
   20.98 -lemma cong_mult_lcancel: assumes an: "coprime a n" and axy:"[a * x = a * y] (mod n)"
   20.99 -  shows "[x = y] (mod n)"
  20.100 -proof-
  20.101 -  {assume "a = 0" with an axy coprime_0'[of n] have ?thesis by (simp add: modeq_def) }
  20.102 -  moreover
  20.103 -  {assume az: "a\<noteq>0"
  20.104 -    {assume xy: "x \<le> y" hence axy': "a*x \<le> a*y" by simp
  20.105 -      with axy cong_sub_cases[of "a*x" "a*y" n]  have "[a*(y - x) = 0] (mod n)"
  20.106 -        by (simp only: if_True diff_mult_distrib2)
  20.107 -      hence th: "n dvd a*(y -x)" by simp
  20.108 -      from coprime_divprod[OF th] an have "n dvd y - x"
  20.109 -        by (simp add: coprime_commute)
  20.110 -      hence ?thesis using xy cong_sub_cases[of x y n] by simp}
  20.111 -    moreover
  20.112 -    {assume H: "\<not>x \<le> y" hence xy: "y \<le> x"  by arith
  20.113 -      from H az have axy': "\<not> a*x \<le> a*y" by auto
  20.114 -      with axy H cong_sub_cases[of "a*x" "a*y" n]  have "[a*(x - y) = 0] (mod n)"
  20.115 -        by (simp only: if_False diff_mult_distrib2)
  20.116 -      hence th: "n dvd a*(x - y)" by simp
  20.117 -      from coprime_divprod[OF th] an have "n dvd x - y"
  20.118 -        by (simp add: coprime_commute)
  20.119 -      hence ?thesis using xy cong_sub_cases[of x y n] by simp}
  20.120 -    ultimately have ?thesis by blast}
  20.121 -  ultimately show ?thesis by blast
  20.122 -qed
  20.123 -
  20.124 -lemma cong_mult_rcancel: assumes an: "coprime a n" and axy:"[x*a = y*a] (mod n)"
  20.125 -  shows "[x = y] (mod n)"
  20.126 -  using cong_mult_lcancel[OF an axy[unfolded mult.commute[of _a]]] .
  20.127 -
  20.128 -lemma cong_refl: "[x = x] (mod n)" by (simp add: modeq_def)
  20.129 -
  20.130 -lemma eq_imp_cong: "a = b \<Longrightarrow> [a = b] (mod n)" by (simp add: cong_refl)
  20.131 -
  20.132 -lemma cong_commute: "[x = y] (mod n) \<longleftrightarrow> [y = x] (mod n)"
  20.133 -  by (auto simp add: modeq_def)
  20.134 -
  20.135 -lemma cong_trans[trans]: "[x = y] (mod n) \<Longrightarrow> [y = z] (mod n) \<Longrightarrow> [x = z] (mod n)"
  20.136 -  by (simp add: modeq_def)
  20.137 -
  20.138 -lemma cong_add: assumes xx': "[x = x'] (mod n)" and yy':"[y = y'] (mod n)"
  20.139 -  shows "[x + y = x' + y'] (mod n)"
  20.140 -proof-
  20.141 -  have "(x + y) mod n = (x mod n + y mod n) mod n"
  20.142 -    by (simp add: mod_add_left_eq[of x y n] mod_add_right_eq[of "x mod n" y n])
  20.143 -  also have "\<dots> = (x' mod n + y' mod n) mod n" using xx' yy' modeq_def by simp
  20.144 -  also have "\<dots> = (x' + y') mod n"
  20.145 -    by (simp add: mod_add_left_eq[of x' y' n] mod_add_right_eq[of "x' mod n" y' n])
  20.146 -  finally show ?thesis unfolding modeq_def .
  20.147 -qed
  20.148 -
  20.149 -lemma cong_mult: assumes xx': "[x = x'] (mod n)" and yy':"[y = y'] (mod n)"
  20.150 -  shows "[x * y = x' * y'] (mod n)"
  20.151 -proof-
  20.152 -  have "(x * y) mod n = (x mod n) * (y mod n) mod n"
  20.153 -    by (simp add: mod_mult_left_eq[of x y n] mod_mult_right_eq[of "x mod n" y n])
  20.154 -  also have "\<dots> = (x' mod n) * (y' mod n) mod n" using xx'[unfolded modeq_def] yy'[unfolded modeq_def] by simp
  20.155 -  also have "\<dots> = (x' * y') mod n"
  20.156 -    by (simp add: mod_mult_left_eq[of x' y' n] mod_mult_right_eq[of "x' mod n" y' n])
  20.157 -  finally show ?thesis unfolding modeq_def .
  20.158 -qed
  20.159 -
  20.160 -lemma cong_exp: "[x = y] (mod n) \<Longrightarrow> [x^k = y^k] (mod n)"
  20.161 -  by (induct k, auto simp add: cong_refl cong_mult)
  20.162 -lemma cong_sub: assumes xx': "[x = x'] (mod n)" and yy': "[y = y'] (mod n)"
  20.163 -  and yx: "y <= x" and yx': "y' <= x'"
  20.164 -  shows "[x - y = x' - y'] (mod n)"
  20.165 -proof-
  20.166 -  { fix x a x' a' y b y' b'
  20.167 -    have "(x::nat) + a = x' + a' \<Longrightarrow> y + b = y' + b' \<Longrightarrow> y <= x \<Longrightarrow> y' <= x'
  20.168 -      \<Longrightarrow> (x - y) + (a + b') = (x' - y') + (a' + b)" by arith}
  20.169 -  note th = this
  20.170 -  from xx' yy' obtain q1 q2 q1' q2' where q12: "x + n*q1 = x'+n*q2"
  20.171 -    and q12': "y + n*q1' = y'+n*q2'" unfolding nat_mod by blast+
  20.172 -  from th[OF q12 q12' yx yx']
  20.173 -  have "(x - y) + n*(q1 + q2') = (x' - y') + n*(q2 + q1')"
  20.174 -    by (simp add: distrib_left)
  20.175 -  thus ?thesis unfolding nat_mod by blast
  20.176 -qed
  20.177 -
  20.178 -lemma cong_mult_lcancel_eq: assumes an: "coprime a n"
  20.179 -  shows "[a * x = a * y] (mod n) \<longleftrightarrow> [x = y] (mod n)" (is "?lhs \<longleftrightarrow> ?rhs")
  20.180 -proof
  20.181 -  assume H: "?rhs" from cong_mult[OF cong_refl[of a n] H] show ?lhs .
  20.182 -next
  20.183 -  assume H: "?lhs" hence H': "[x*a = y*a] (mod n)" by (simp add: mult.commute)
  20.184 -  from cong_mult_rcancel[OF an H'] show ?rhs  .
  20.185 -qed
  20.186 -
  20.187 -lemma cong_mult_rcancel_eq: assumes an: "coprime a n"
  20.188 -  shows "[x * a = y * a] (mod n) \<longleftrightarrow> [x = y] (mod n)"
  20.189 -using cong_mult_lcancel_eq[OF an, of x y] by (simp add: mult.commute)
  20.190 -
  20.191 -lemma cong_add_lcancel_eq: "[a + x = a + y] (mod n) \<longleftrightarrow> [x = y] (mod n)"
  20.192 -  by (simp add: nat_mod)
  20.193 -
  20.194 -lemma cong_add_rcancel_eq: "[x + a = y + a] (mod n) \<longleftrightarrow> [x = y] (mod n)"
  20.195 -  by (simp add: nat_mod)
  20.196 -
  20.197 -lemma cong_add_rcancel: "[x + a = y + a] (mod n) \<Longrightarrow> [x = y] (mod n)"
  20.198 -  by (simp add: nat_mod)
  20.199 -
  20.200 -lemma cong_add_lcancel: "[a + x = a + y] (mod n) \<Longrightarrow> [x = y] (mod n)"
  20.201 -  by (simp add: nat_mod)
  20.202 -
  20.203 -lemma cong_add_lcancel_eq_0: "[a + x = a] (mod n) \<longleftrightarrow> [x = 0] (mod n)"
  20.204 -  by (simp add: nat_mod)
  20.205 -
  20.206 -lemma cong_add_rcancel_eq_0: "[x + a = a] (mod n) \<longleftrightarrow> [x = 0] (mod n)"
  20.207 -  by (simp add: nat_mod)
  20.208 -
  20.209 -lemma cong_imp_eq: assumes xn: "x < n" and yn: "y < n" and xy: "[x = y] (mod n)"
  20.210 -  shows "x = y"
  20.211 -  using xy[unfolded modeq_def mod_less[OF xn] mod_less[OF yn]] .
  20.212 -
  20.213 -lemma cong_divides_modulus: "[x = y] (mod m) \<Longrightarrow> n dvd m ==> [x = y] (mod n)"
  20.214 -  apply (auto simp add: nat_mod dvd_def)
  20.215 -  apply (rule_tac x="k*q1" in exI)
  20.216 -  apply (rule_tac x="k*q2" in exI)
  20.217 -  by simp
  20.218 -
  20.219 -lemma cong_0_divides: "[x = 0] (mod n) \<longleftrightarrow> n dvd x" by simp
  20.220 -
  20.221 -lemma cong_1_divides:"[x = 1] (mod n) ==> n dvd x - 1"
  20.222 -  apply (cases "x\<le>1", simp_all)
  20.223 -  using cong_sub_cases[of x 1 n] by auto
  20.224 -
  20.225 -lemma cong_divides: "[x = y] (mod n) \<Longrightarrow> n dvd x \<longleftrightarrow> n dvd y"
  20.226 -apply (auto simp add: nat_mod dvd_def)
  20.227 -apply (rule_tac x="k + q1 - q2" in exI, simp add: add_mult_distrib2 diff_mult_distrib2)
  20.228 -apply (rule_tac x="k + q2 - q1" in exI, simp add: add_mult_distrib2 diff_mult_distrib2)
  20.229 -done
  20.230 -
  20.231 -lemma cong_coprime: assumes xy: "[x = y] (mod n)"
  20.232 -  shows "coprime n x \<longleftrightarrow> coprime n y"
  20.233 -proof-
  20.234 -  {assume "n=0" hence ?thesis using xy by simp}
  20.235 -  moreover
  20.236 -  {assume nz: "n \<noteq> 0"
  20.237 -  have "coprime n x \<longleftrightarrow> coprime (x mod n) n"
  20.238 -    by (simp add: coprime_mod[OF nz, of x] coprime_commute[of n x])
  20.239 -  also have "\<dots> \<longleftrightarrow> coprime (y mod n) n" using xy[unfolded modeq_def] by simp
  20.240 -  also have "\<dots> \<longleftrightarrow> coprime y n" by (simp add: coprime_mod[OF nz, of y])
  20.241 -  finally have ?thesis by (simp add: coprime_commute) }
  20.242 -ultimately show ?thesis by blast
  20.243 -qed
  20.244 -
  20.245 -lemma cong_mod: "~(n = 0) \<Longrightarrow> [a mod n = a] (mod n)" by (simp add: modeq_def)
  20.246 -
  20.247 -lemma mod_mult_cong: "~(a = 0) \<Longrightarrow> ~(b = 0)
  20.248 -  \<Longrightarrow> [x mod (a * b) = y] (mod a) \<longleftrightarrow> [x = y] (mod a)"
  20.249 -  by (simp add: modeq_def mod_mult2_eq mod_add_left_eq)
  20.250 -
  20.251 -lemma cong_mod_mult: "[x = y] (mod n) \<Longrightarrow> m dvd n \<Longrightarrow> [x = y] (mod m)"
  20.252 -  apply (auto simp add: nat_mod dvd_def)
  20.253 -  apply (rule_tac x="k*q1" in exI)
  20.254 -  apply (rule_tac x="k*q2" in exI, simp)
  20.255 -  done
  20.256 -
  20.257 -(* Some things when we know more about the order.                            *)
  20.258 -
  20.259 -lemma cong_le: "y <= x \<Longrightarrow> [x = y] (mod n) \<longleftrightarrow> (\<exists>q. x = q * n + y)"
  20.260 -  using nat_mod_lemma[of x y n]
  20.261 -  apply auto
  20.262 -  apply (simp add: nat_mod)
  20.263 -  apply (rule_tac x="q" in exI)
  20.264 -  apply (rule_tac x="q + q" in exI)
  20.265 -  by (auto simp: algebra_simps)
  20.266 -
  20.267 -lemma cong_to_1: "[a = 1] (mod n) \<longleftrightarrow> a = 0 \<and> n = 1 \<or> (\<exists>m. a = 1 + m * n)"
  20.268 -proof-
  20.269 -  {assume "n = 0 \<or> n = 1\<or> a = 0 \<or> a = 1" hence ?thesis
  20.270 -      apply (cases "n=0", simp_all add: cong_commute)
  20.271 -      apply (cases "n=1", simp_all add: cong_commute modeq_def)
  20.272 -      apply arith
  20.273 -      apply (cases "a=1")
  20.274 -      apply (simp_all add: modeq_def cong_commute)
  20.275 -      done }
  20.276 -  moreover
  20.277 -  {assume n: "n\<noteq>0" "n\<noteq>1" and a:"a\<noteq>0" "a \<noteq> 1" hence a': "a \<ge> 1" by simp
  20.278 -    hence ?thesis using cong_le[OF a', of n] by auto }
  20.279 -  ultimately show ?thesis by auto
  20.280 -qed
  20.281 -
  20.282 -(* Some basic theorems about solving congruences.                            *)
  20.283 -
  20.284 -
  20.285 -lemma cong_solve: assumes an: "coprime a n" shows "\<exists>x. [a * x = b] (mod n)"
  20.286 -proof-
  20.287 -  {assume "a=0" hence ?thesis using an by (simp add: modeq_def)}
  20.288 -  moreover
  20.289 -  {assume az: "a\<noteq>0"
  20.290 -  from bezout_add_strong[OF az, of n]
  20.291 -  obtain d x y where dxy: "d dvd a" "d dvd n" "a*x = n*y + d" by blast
  20.292 -  from an[unfolded coprime, rule_format, of d] dxy(1,2) have d1: "d = 1" by blast
  20.293 -  hence "a*x*b = (n*y + 1)*b" using dxy(3) by simp
  20.294 -  hence "a*(x*b) = n*(y*b) + b" by algebra
  20.295 -  hence "a*(x*b) mod n = (n*(y*b) + b) mod n" by simp
  20.296 -  hence "a*(x*b) mod n = b mod n" by (simp add: mod_add_left_eq)
  20.297 -  hence "[a*(x*b) = b] (mod n)" unfolding modeq_def .
  20.298 -  hence ?thesis by blast}
  20.299 -ultimately  show ?thesis by blast
  20.300 -qed
  20.301 -
  20.302 -lemma cong_solve_unique: assumes an: "coprime a n" and nz: "n \<noteq> 0"
  20.303 -  shows "\<exists>!x. x < n \<and> [a * x = b] (mod n)"
  20.304 -proof-
  20.305 -  let ?P = "\<lambda>x. x < n \<and> [a * x = b] (mod n)"
  20.306 -  from cong_solve[OF an] obtain x where x: "[a*x = b] (mod n)" by blast
  20.307 -  let ?x = "x mod n"
  20.308 -  from x have th: "[a * ?x = b] (mod n)"
  20.309 -    by (simp add: modeq_def mod_mult_right_eq[of a x n])
  20.310 -  from mod_less_divisor[ of n x] nz th have Px: "?P ?x" by simp
  20.311 -  {fix y assume Py: "y < n" "[a * y = b] (mod n)"
  20.312 -    from Py(2) th have "[a * y = a*?x] (mod n)" by (simp add: modeq_def)
  20.313 -    hence "[y = ?x] (mod n)" by (simp add: cong_mult_lcancel_eq[OF an])
  20.314 -    with mod_less[OF Py(1)] mod_less_divisor[ of n x] nz
  20.315 -    have "y = ?x" by (simp add: modeq_def)}
  20.316 -  with Px show ?thesis by blast
  20.317 -qed
  20.318 -
  20.319 -lemma cong_solve_unique_nontrivial:
  20.320 -  assumes p: "prime p" and pa: "coprime p a" and x0: "0 < x" and xp: "x < p"
  20.321 -  shows "\<exists>!y. 0 < y \<and> y < p \<and> [x * y = a] (mod p)"
  20.322 -proof-
  20.323 -  from p have p1: "p > 1" using prime_ge_2[OF p] by arith
  20.324 -  hence p01: "p \<noteq> 0" "p \<noteq> 1" by arith+
  20.325 -  from pa have ap: "coprime a p" by (simp add: coprime_commute)
  20.326 -  from prime_coprime[OF p, of x] dvd_imp_le[of p x] x0 xp have px:"coprime x p"
  20.327 -    by (auto simp add: coprime_commute)
  20.328 -  from cong_solve_unique[OF px p01(1)]
  20.329 -  obtain y where y: "y < p" "[x * y = a] (mod p)" "\<forall>z. z < p \<and> [x * z = a] (mod p) \<longrightarrow> z = y" by blast
  20.330 -  {assume y0: "y = 0"
  20.331 -    with y(2) have th: "p dvd a" by (simp add: cong_commute[of 0 a p])
  20.332 -    with p coprime_prime[OF pa, of p] have False by simp}
  20.333 -  with y show ?thesis unfolding Ex1_def using neq0_conv by blast
  20.334 -qed
  20.335 -lemma cong_unique_inverse_prime:
  20.336 -  assumes p: "prime p" and x0: "0 < x" and xp: "x < p"
  20.337 -  shows "\<exists>!y. 0 < y \<and> y < p \<and> [x * y = 1] (mod p)"
  20.338 -  using cong_solve_unique_nontrivial[OF p coprime_1[of p] x0 xp] .
  20.339 -
  20.340 -(* Forms of the Chinese remainder theorem.                                   *)
  20.341 -
  20.342 -lemma cong_chinese:
  20.343 -  assumes ab: "coprime a b" and  xya: "[x = y] (mod a)"
  20.344 -  and xyb: "[x = y] (mod b)"
  20.345 -  shows "[x = y] (mod a*b)"
  20.346 -  using ab xya xyb
  20.347 -  by (simp add: cong_sub_cases[of x y a] cong_sub_cases[of x y b]
  20.348 -    cong_sub_cases[of x y "a*b"])
  20.349 -(cases "x \<le> y", simp_all add: divides_mul[of a _ b])
  20.350 -
  20.351 -lemma chinese_remainder_unique:
  20.352 -  assumes ab: "coprime a b" and az: "a \<noteq> 0" and bz: "b\<noteq>0"
  20.353 -  shows "\<exists>!x. x < a * b \<and> [x = m] (mod a) \<and> [x = n] (mod b)"
  20.354 -proof-
  20.355 -  from az bz have abpos: "a*b > 0" by simp
  20.356 -  from chinese_remainder[OF ab az bz] obtain x q1 q2 where
  20.357 -    xq12: "x = m + q1 * a" "x = n + q2 * b" by blast
  20.358 -  let ?w = "x mod (a*b)"
  20.359 -  have wab: "?w < a*b" by (simp add: mod_less_divisor[OF abpos])
  20.360 -  from xq12(1) have "?w mod a = ((m + q1 * a) mod (a*b)) mod a" by simp
  20.361 -  also have "\<dots> = m mod a" by (simp add: mod_mult2_eq)
  20.362 -  finally have th1: "[?w = m] (mod a)" by (simp add: modeq_def)
  20.363 -  from xq12(2) have "?w mod b = ((n + q2 * b) mod (a*b)) mod b" by simp
  20.364 -  also have "\<dots> = ((n + q2 * b) mod (b*a)) mod b" by (simp add: mult.commute)
  20.365 -  also have "\<dots> = n mod b" by (simp add: mod_mult2_eq)
  20.366 -  finally have th2: "[?w = n] (mod b)" by (simp add: modeq_def)
  20.367 -  {fix y assume H: "y < a*b" "[y = m] (mod a)" "[y = n] (mod b)"
  20.368 -    with th1 th2 have H': "[y = ?w] (mod a)" "[y = ?w] (mod b)"
  20.369 -      by (simp_all add: modeq_def)
  20.370 -    from cong_chinese[OF ab H'] mod_less[OF H(1)] mod_less[OF wab]
  20.371 -    have "y = ?w" by (simp add: modeq_def)}
  20.372 -  with th1 th2 wab show ?thesis by blast
  20.373 -qed
  20.374 -
  20.375 -lemma chinese_remainder_coprime_unique:
  20.376 -  assumes ab: "coprime a b" and az: "a \<noteq> 0" and bz: "b \<noteq> 0"
  20.377 -  and ma: "coprime m a" and nb: "coprime n b"
  20.378 -  shows "\<exists>!x. coprime x (a * b) \<and> x < a * b \<and> [x = m] (mod a) \<and> [x = n] (mod b)"
  20.379 -proof-
  20.380 -  let ?P = "\<lambda>x. x < a * b \<and> [x = m] (mod a) \<and> [x = n] (mod b)"
  20.381 -  from chinese_remainder_unique[OF ab az bz]
  20.382 -  obtain x where x: "x < a * b" "[x = m] (mod a)" "[x = n] (mod b)"
  20.383 -    "\<forall>y. ?P y \<longrightarrow> y = x" by blast
  20.384 -  from ma nb cong_coprime[OF x(2)] cong_coprime[OF x(3)]
  20.385 -  have "coprime x a" "coprime x b" by (simp_all add: coprime_commute)
  20.386 -  with coprime_mul[of x a b] have "coprime x (a*b)" by simp
  20.387 -  with x show ?thesis by blast
  20.388 -qed
  20.389 -
  20.390 -(* Euler totient function.                                                   *)
  20.391 -
  20.392 -definition phi_def: "\<phi> n = card { m. 0 < m \<and> m <= n \<and> coprime m n }"
  20.393 -
  20.394 -lemma phi_0[simp]: "\<phi> 0 = 0"
  20.395 -  unfolding phi_def by auto
  20.396 -
  20.397 -lemma phi_finite[simp]: "finite ({ m. 0 < m \<and> m <= n \<and> coprime m n })"
  20.398 -proof-
  20.399 -  have "{ m. 0 < m \<and> m <= n \<and> coprime m n } \<subseteq> {0..n}" by auto
  20.400 -  thus ?thesis by (auto intro: finite_subset)
  20.401 -qed
  20.402 -
  20.403 -declare coprime_1[presburger]
  20.404 -lemma phi_1[simp]: "\<phi> 1 = 1"
  20.405 -proof-
  20.406 -  {fix m
  20.407 -    have "0 < m \<and> m <= 1 \<and> coprime m 1 \<longleftrightarrow> m = 1" by presburger }
  20.408 -  thus ?thesis by (simp add: phi_def)
  20.409 -qed
  20.410 -
  20.411 -lemma [simp]: "\<phi> (Suc 0) = Suc 0" using phi_1 by simp
  20.412 -
  20.413 -lemma phi_alt: "\<phi>(n) = card { m. coprime m n \<and> m < n}"
  20.414 -proof-
  20.415 -  {assume "n=0 \<or> n=1" hence ?thesis by (cases "n=0", simp_all)}
  20.416 -  moreover
  20.417 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.418 -    {fix m
  20.419 -      from n have "0 < m \<and> m <= n \<and> coprime m n \<longleftrightarrow> coprime m n \<and> m < n"
  20.420 -        apply (cases "m = 0", simp_all)
  20.421 -        apply (cases "m = 1", simp_all)
  20.422 -        apply (cases "m = n", auto)
  20.423 -        done }
  20.424 -    hence ?thesis unfolding phi_def by simp}
  20.425 -  ultimately show ?thesis by auto
  20.426 -qed
  20.427 -
  20.428 -lemma phi_finite_lemma[simp]: "finite {m. coprime m n \<and>  m < n}" (is "finite ?S")
  20.429 -  by (rule finite_subset[of "?S" "{0..n}"], auto)
  20.430 -
  20.431 -lemma phi_another: assumes n: "n\<noteq>1"
  20.432 -  shows "\<phi> n = card {m. 0 < m \<and> m < n \<and> coprime m n }"
  20.433 -proof-
  20.434 -  {fix m
  20.435 -    from n have "0 < m \<and> m < n \<and> coprime m n \<longleftrightarrow> coprime m n \<and> m < n"
  20.436 -      by (cases "m=0", auto)}
  20.437 -  thus ?thesis unfolding phi_alt by auto
  20.438 -qed
  20.439 -
  20.440 -lemma phi_limit: "\<phi> n \<le> n"
  20.441 -proof-
  20.442 -  have "{ m. coprime m n \<and> m < n} \<subseteq> {0 ..<n}" by auto
  20.443 -  with card_mono[of "{0 ..<n}" "{ m. coprime m n \<and> m < n}"]
  20.444 -  show ?thesis unfolding phi_alt by auto
  20.445 -qed
  20.446 -
  20.447 -lemma stupid[simp]: "{m. (0::nat) < m \<and> m < n} = {1..<n}"
  20.448 -  by auto
  20.449 -
  20.450 -lemma phi_limit_strong: assumes n: "n\<noteq>1"
  20.451 -  shows "\<phi>(n) \<le> n - 1"
  20.452 -proof-
  20.453 -  show ?thesis
  20.454 -    unfolding phi_another[OF n] finite_number_segment[of n, symmetric]
  20.455 -    by (rule card_mono[of "{m. 0 < m \<and> m < n}" "{m. 0 < m \<and> m < n \<and> coprime m n}"], auto)
  20.456 -qed
  20.457 -
  20.458 -lemma phi_lowerbound_1_strong: assumes n: "n \<ge> 1"
  20.459 -  shows "\<phi>(n) \<ge> 1"
  20.460 -proof-
  20.461 -  let ?S = "{ m. 0 < m \<and> m <= n \<and> coprime m n }"
  20.462 -  from card_0_eq[of ?S] n have "\<phi> n \<noteq> 0" unfolding phi_alt
  20.463 -    apply auto
  20.464 -    apply (cases "n=1", simp_all)
  20.465 -    apply (rule exI[where x=1], simp)
  20.466 -    done
  20.467 -  thus ?thesis by arith
  20.468 -qed
  20.469 -
  20.470 -lemma phi_lowerbound_1: "2 <= n ==> 1 <= \<phi>(n)"
  20.471 -  using phi_lowerbound_1_strong[of n] by auto
  20.472 -
  20.473 -lemma phi_lowerbound_2: assumes n: "3 <= n" shows "2 <= \<phi> (n)"
  20.474 -proof-
  20.475 -  let ?S = "{ m. 0 < m \<and> m <= n \<and> coprime m n }"
  20.476 -  have inS: "{1, n - 1} \<subseteq> ?S" using n coprime_plus1[of "n - 1"]
  20.477 -    by (auto simp add: coprime_commute)
  20.478 -  from n have c2: "card {1, n - 1} = 2" by (auto simp add: card_insert_if)
  20.479 -  from card_mono[of ?S "{1, n - 1}", simplified inS c2] show ?thesis
  20.480 -    unfolding phi_def by auto
  20.481 -qed
  20.482 -
  20.483 -lemma phi_prime: "\<phi> n = n - 1 \<and> n\<noteq>0 \<and> n\<noteq>1 \<longleftrightarrow> prime n"
  20.484 -proof-
  20.485 -  {assume "n=0 \<or> n=1" hence ?thesis by (cases "n=1", simp_all)}
  20.486 -  moreover
  20.487 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.488 -    let ?S = "{m. 0 < m \<and> m < n}"
  20.489 -    have fS: "finite ?S" by simp
  20.490 -    let ?S' = "{m. 0 < m \<and> m < n \<and> coprime m n}"
  20.491 -    have fS':"finite ?S'" apply (rule finite_subset[of ?S' ?S]) by auto
  20.492 -    {assume H: "\<phi> n = n - 1 \<and> n\<noteq>0 \<and> n\<noteq>1"
  20.493 -      hence ceq: "card ?S' = card ?S"
  20.494 -      using n finite_number_segment[of n] phi_another[OF n(2)] by simp
  20.495 -      {fix m assume m: "0 < m" "m < n" "\<not> coprime m n"
  20.496 -        hence mS': "m \<notin> ?S'" by auto
  20.497 -        have "insert m ?S' \<le> ?S" using m by auto
  20.498 -        have "card (insert m ?S') \<le> card ?S"
  20.499 -          by (rule card_mono[of ?S "insert m ?S'"]) (use m in auto)
  20.500 -        hence False
  20.501 -          unfolding card_insert_disjoint[of "?S'" m, OF fS' mS'] ceq
  20.502 -          by simp }
  20.503 -      hence "\<forall>m. 0 <m \<and> m < n \<longrightarrow> coprime m n" by blast
  20.504 -      hence "prime n" unfolding prime using n by (simp add: coprime_commute)}
  20.505 -    moreover
  20.506 -    {assume H: "prime n"
  20.507 -      hence "?S = ?S'" unfolding prime using n
  20.508 -        by (auto simp add: coprime_commute)
  20.509 -      hence "card ?S = card ?S'" by simp
  20.510 -      hence "\<phi> n = n - 1" unfolding phi_another[OF n(2)] by simp}
  20.511 -    ultimately have ?thesis using n by blast}
  20.512 -  ultimately show ?thesis by (cases "n=0") blast+
  20.513 -qed
  20.514 -
  20.515 -(* Multiplicativity property.                                                *)
  20.516 -
  20.517 -lemma phi_multiplicative: assumes ab: "coprime a b"
  20.518 -  shows "\<phi> (a * b) = \<phi> a * \<phi> b"
  20.519 -proof-
  20.520 -  {assume "a = 0 \<or> b = 0 \<or> a = 1 \<or> b = 1"
  20.521 -    hence ?thesis
  20.522 -      by (cases "a=0", simp, cases "b=0", simp, cases"a=1", simp_all) }
  20.523 -  moreover
  20.524 -  {assume a: "a\<noteq>0" "a\<noteq>1" and b: "b\<noteq>0" "b\<noteq>1"
  20.525 -    hence ab0: "a*b \<noteq> 0" by simp
  20.526 -    let ?S = "\<lambda>k. {m. coprime m k \<and> m < k}"
  20.527 -    let ?f = "\<lambda>x. (x mod a, x mod b)"
  20.528 -    have eq: "?f ` (?S (a*b)) = (?S a \<times> ?S b)"
  20.529 -    proof-
  20.530 -      {fix x assume x:"x \<in> ?S (a*b)"
  20.531 -        hence x': "coprime x (a*b)" "x < a*b" by simp_all
  20.532 -        hence xab: "coprime x a" "coprime x b" by (simp_all add: coprime_mul_eq)
  20.533 -        from mod_less_divisor a b have xab':"x mod a < a" "x mod b < b" by auto
  20.534 -        from xab xab' have "?f x \<in> (?S a \<times> ?S b)"
  20.535 -          by (simp add: coprime_mod[OF a(1)] coprime_mod[OF b(1)])}
  20.536 -      moreover
  20.537 -      {fix x y assume x: "x \<in> ?S a" and y: "y \<in> ?S b"
  20.538 -        hence x': "coprime x a" "x < a" and y': "coprime y b" "y < b" by simp_all
  20.539 -        from chinese_remainder_coprime_unique[OF ab a(1) b(1) x'(1) y'(1)]
  20.540 -        obtain z where z: "coprime z (a * b)" "z < a * b" "[z = x] (mod a)"
  20.541 -          "[z = y] (mod b)" by blast
  20.542 -        hence "(x,y) \<in> ?f ` (?S (a*b))"
  20.543 -          using y'(2) mod_less_divisor[of b y] x'(2) mod_less_divisor[of a x]
  20.544 -          by (auto simp add: image_iff modeq_def)}
  20.545 -      ultimately show ?thesis by auto
  20.546 -    qed
  20.547 -    have finj: "inj_on ?f (?S (a*b))"
  20.548 -      unfolding inj_on_def
  20.549 -    proof(clarify)
  20.550 -      fix x y assume H: "coprime x (a * b)" "x < a * b" "coprime y (a * b)"
  20.551 -        "y < a * b" "x mod a = y mod a" "x mod b = y mod b"
  20.552 -      hence cp: "coprime x a" "coprime x b" "coprime y a" "coprime y b"
  20.553 -        by (simp_all add: coprime_mul_eq)
  20.554 -      from chinese_remainder_coprime_unique[OF ab a(1) b(1) cp(3,4)] H
  20.555 -      show "x = y" unfolding modeq_def by blast
  20.556 -    qed
  20.557 -    from card_image[OF finj, unfolded eq] have ?thesis
  20.558 -      unfolding phi_alt by simp }
  20.559 -  ultimately show ?thesis by auto
  20.560 -qed
  20.561 -
  20.562 -(* Fermat's Little theorem / Fermat-Euler theorem.                           *)
  20.563 -
  20.564 -
  20.565 -lemma nproduct_mod:
  20.566 -  assumes fS: "finite S" and n0: "n \<noteq> 0"
  20.567 -  shows "[prod (\<lambda>m. a(m) mod n) S = prod a S] (mod n)"
  20.568 -proof-
  20.569 -  have th1:"[1 = 1] (mod n)" by (simp add: modeq_def)
  20.570 -  from cong_mult
  20.571 -  have th3:"\<forall>x1 y1 x2 y2.
  20.572 -    [x1 = x2] (mod n) \<and> [y1 = y2] (mod n) \<longrightarrow> [x1 * y1 = x2 * y2] (mod n)"
  20.573 -    by blast
  20.574 -  have th4:"\<forall>x\<in>S. [a x mod n = a x] (mod n)" by (simp add: modeq_def)
  20.575 -  from prod.related [where h="(\<lambda>m. a(m) mod n)" and g=a, OF th1 th3 fS, OF th4] show ?thesis by (simp add: fS)
  20.576 -qed
  20.577 -
  20.578 -lemma nproduct_cmul:
  20.579 -  assumes fS:"finite S"
  20.580 -  shows "prod (\<lambda>m. (c::'a::{comm_monoid_mult})* a(m)) S = c ^ (card S) * prod a S"
  20.581 -unfolding prod.distrib prod_constant [of c] ..
  20.582 -
  20.583 -lemma coprime_nproduct:
  20.584 -  assumes fS: "finite S" and Sn: "\<forall>x\<in>S. coprime n (a x)"
  20.585 -  shows "coprime n (prod a S)"
  20.586 -  using fS by (rule finite_subset_induct)
  20.587 -    (insert Sn, auto simp add: coprime_mul)
  20.588 -
  20.589 -lemma fermat_little: assumes an: "coprime a n"
  20.590 -  shows "[a ^ (\<phi> n) = 1] (mod n)"
  20.591 -proof-
  20.592 -  {assume "n=0" hence ?thesis by simp}
  20.593 -  moreover
  20.594 -  {assume "n=1" hence ?thesis by (simp add: modeq_def)}
  20.595 -  moreover
  20.596 -  {assume nz: "n \<noteq> 0" and n1: "n \<noteq> 1"
  20.597 -    let ?S = "{m. coprime m n \<and> m < n}"
  20.598 -    let ?P = "\<Prod> ?S"
  20.599 -    have fS: "finite ?S" by simp
  20.600 -    have cardfS: "\<phi> n = card ?S" unfolding phi_alt ..
  20.601 -    {fix m assume m: "m \<in> ?S"
  20.602 -      hence "coprime m n" by simp
  20.603 -      with coprime_mul[of n a m] an have "coprime (a*m) n"
  20.604 -        by (simp add: coprime_commute)}
  20.605 -    hence Sn: "\<forall>m\<in> ?S. coprime (a*m) n " by blast
  20.606 -    from coprime_nproduct[OF fS, of n "\<lambda>m. m"] have nP:"coprime ?P n"
  20.607 -      by (simp add: coprime_commute)
  20.608 -    have Paphi: "[?P*a^ (\<phi> n) = ?P*1] (mod n)"
  20.609 -    proof-
  20.610 -      let ?h = "\<lambda>m. (a * m) mod n"
  20.611 -      
  20.612 -      have eq0: "(\<Prod>i\<in>?S. ?h i) = (\<Prod>i\<in>?S. i)"
  20.613 -      proof (rule prod.reindex_bij_betw)
  20.614 -        have "inj_on (\<lambda>i. ?h i) ?S"
  20.615 -        proof (rule inj_onI)
  20.616 -          fix x y assume "?h x = ?h y"
  20.617 -          then have "[a * x = a * y] (mod n)"
  20.618 -            by (simp add: modeq_def)
  20.619 -          moreover assume "x \<in> ?S" "y \<in> ?S"
  20.620 -          ultimately show "x = y"
  20.621 -            by (auto intro: cong_imp_eq cong_mult_lcancel an)
  20.622 -        qed
  20.623 -        moreover have "?h ` ?S = ?S"
  20.624 -        proof safe
  20.625 -          fix y assume "coprime y n" then show "coprime (?h y) n"
  20.626 -            by (metis an nz coprime_commute coprime_mod coprime_mul_eq)
  20.627 -        next
  20.628 -          fix y assume y: "coprime y n" "y < n"
  20.629 -          from cong_solve_unique[OF an nz] obtain x where x: "x < n" "[a * x = y] (mod n)"
  20.630 -            by blast
  20.631 -          then show "y \<in> ?h ` ?S"
  20.632 -            using cong_coprime[OF x(2)] coprime_mul_eq[of n a x] an y x
  20.633 -            by (intro image_eqI[of _ _ x]) (auto simp add: coprime_commute modeq_def)
  20.634 -        qed (insert nz, simp)
  20.635 -        ultimately show "bij_betw ?h ?S ?S"
  20.636 -          by (simp add: bij_betw_def)
  20.637 -      qed
  20.638 -      from nproduct_mod[OF fS nz, of "op * a"]
  20.639 -      have "[(\<Prod>i\<in>?S. a * i) = (\<Prod>i\<in>?S. ?h i)] (mod n)"
  20.640 -        by (simp add: cong_commute)
  20.641 -      also have "[(\<Prod>i\<in>?S. ?h i) = ?P] (mod n)"
  20.642 -        using eq0 fS an by (simp add: prod_def modeq_def)
  20.643 -      finally show "[?P*a^ (\<phi> n) = ?P*1] (mod n)"
  20.644 -        unfolding cardfS mult.commute[of ?P "a^ (card ?S)"]
  20.645 -          nproduct_cmul[OF fS, symmetric] mult_1_right by simp
  20.646 -    qed
  20.647 -    from cong_mult_lcancel[OF nP Paphi] have ?thesis . }
  20.648 -  ultimately show ?thesis by blast
  20.649 -qed
  20.650 -
  20.651 -lemma fermat_little_prime: assumes p: "prime p" and ap: "coprime a p"
  20.652 -  shows "[a^ (p - 1) = 1] (mod p)"
  20.653 -  using fermat_little[OF ap] p[unfolded phi_prime[symmetric]]
  20.654 -by simp
  20.655 -
  20.656 -
  20.657 -(* Lucas's theorem.                                                          *)
  20.658 -
  20.659 -lemma lucas_coprime_lemma:
  20.660 -  assumes m: "m\<noteq>0" and am: "[a^m = 1] (mod n)"
  20.661 -  shows "coprime a n"
  20.662 -proof-
  20.663 -  {assume "n=1" hence ?thesis by simp}
  20.664 -  moreover
  20.665 -  {assume "n = 0" hence ?thesis using am m exp_eq_1[of a m] by simp}
  20.666 -  moreover
  20.667 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.668 -    from m obtain m' where m': "m = Suc m'" by (cases m, blast+)
  20.669 -    {fix d
  20.670 -      assume d: "d dvd a" "d dvd n"
  20.671 -      from n have n1: "1 < n" by arith
  20.672 -      from am mod_less[OF n1] have am1: "a^m mod n = 1" unfolding modeq_def by simp
  20.673 -      from dvd_mult2[OF d(1), of "a^m'"] have dam:"d dvd a^m" by (simp add: m')
  20.674 -      from dvd_mod_iff[OF d(2), of "a^m"] dam am1
  20.675 -      have "d = 1" by simp }
  20.676 -    hence ?thesis unfolding coprime by auto
  20.677 -  }
  20.678 -  ultimately show ?thesis by blast
  20.679 -qed
  20.680 -
  20.681 -lemma lucas_weak:
  20.682 -  assumes n: "n \<ge> 2" and an:"[a^(n - 1) = 1] (mod n)"
  20.683 -  and nm: "\<forall>m. 0 <m \<and> m < n - 1 \<longrightarrow> \<not> [a^m = 1] (mod n)"
  20.684 -  shows "prime n"
  20.685 -proof-
  20.686 -  from n have n1: "n \<noteq> 1" "n\<noteq>0" "n - 1 \<noteq> 0" "n - 1 > 0" "n - 1 < n" by arith+
  20.687 -  from lucas_coprime_lemma[OF n1(3) an] have can: "coprime a n" .
  20.688 -  from fermat_little[OF can] have afn: "[a ^ \<phi> n = 1] (mod n)" .
  20.689 -  {assume "\<phi> n \<noteq> n - 1"
  20.690 -    with phi_limit_strong[OF n1(1)] phi_lowerbound_1[OF n]
  20.691 -    have c:"\<phi> n > 0 \<and> \<phi> n < n - 1" by arith
  20.692 -    from nm[rule_format, OF c] afn have False ..}
  20.693 -  hence "\<phi> n = n - 1" by blast
  20.694 -  with phi_prime[of n] n1(1,2) show ?thesis by simp
  20.695 -qed
  20.696 -
  20.697 -lemma nat_exists_least_iff: "(\<exists>(n::nat). P n) \<longleftrightarrow> (\<exists>n. P n \<and> (\<forall>m < n. \<not> P m))"
  20.698 -  (is "?lhs \<longleftrightarrow> ?rhs")
  20.699 -proof
  20.700 -  assume ?rhs thus ?lhs by blast
  20.701 -next
  20.702 -  assume H: ?lhs then obtain n where n: "P n" by blast
  20.703 -  let ?x = "Least P"
  20.704 -  {fix m assume m: "m < ?x"
  20.705 -    from not_less_Least[OF m] have "\<not> P m" .}
  20.706 -  with LeastI_ex[OF H] show ?rhs by blast
  20.707 -qed
  20.708 -
  20.709 -lemma nat_exists_least_iff': "(\<exists>(n::nat). P n) \<longleftrightarrow> (P (Least P) \<and> (\<forall>m < (Least P). \<not> P m))"
  20.710 -  (is "?lhs \<longleftrightarrow> ?rhs")
  20.711 -proof-
  20.712 -  {assume ?rhs hence ?lhs by blast}
  20.713 -  moreover
  20.714 -  { assume H: ?lhs then obtain n where n: "P n" by blast
  20.715 -    let ?x = "Least P"
  20.716 -    {fix m assume m: "m < ?x"
  20.717 -      from not_less_Least[OF m] have "\<not> P m" .}
  20.718 -    with LeastI_ex[OF H] have ?rhs by blast}
  20.719 -  ultimately show ?thesis by blast
  20.720 -qed
  20.721 -
  20.722 -lemma power_mod: "((x::nat) mod m)^n mod m = x^n mod m"
  20.723 -proof(induct n)
  20.724 -  case 0 thus ?case by simp
  20.725 -next
  20.726 -  case (Suc n)
  20.727 -  have "(x mod m)^(Suc n) mod m = ((x mod m) * (((x mod m) ^ n) mod m)) mod m"
  20.728 -    by (simp add: mod_mult_right_eq[symmetric])
  20.729 -  also have "\<dots> = ((x mod m) * (x^n mod m)) mod m" using Suc.hyps by simp
  20.730 -  also have "\<dots> = x^(Suc n) mod m"
  20.731 -    by (simp add: mod_mult_left_eq[symmetric] mod_mult_right_eq[symmetric])
  20.732 -  finally show ?case .
  20.733 -qed
  20.734 -
  20.735 -lemma lucas:
  20.736 -  assumes n2: "n \<ge> 2" and an1: "[a^(n - 1) = 1] (mod n)"
  20.737 -  and pn: "\<forall>p. prime p \<and> p dvd n - 1 \<longrightarrow> \<not> [a^((n - 1) div p) = 1] (mod n)"
  20.738 -  shows "prime n"
  20.739 -proof-
  20.740 -  from n2 have n01: "n\<noteq>0" "n\<noteq>1" "n - 1 \<noteq> 0" by arith+
  20.741 -  from mod_less_divisor[of n 1] n01 have onen: "1 mod n = 1" by simp
  20.742 -  from lucas_coprime_lemma[OF n01(3) an1] cong_coprime[OF an1]
  20.743 -  have an: "coprime a n" "coprime (a^(n - 1)) n" by (simp_all add: coprime_commute)
  20.744 -  {assume H0: "\<exists>m. 0 < m \<and> m < n - 1 \<and> [a ^ m = 1] (mod n)" (is "EX m. ?P m")
  20.745 -    from H0[unfolded nat_exists_least_iff[of ?P]] obtain m where
  20.746 -      m: "0 < m" "m < n - 1" "[a ^ m = 1] (mod n)" "\<forall>k <m. \<not>?P k" by blast
  20.747 -    {assume nm1: "(n - 1) mod m > 0"
  20.748 -      from mod_less_divisor[OF m(1)] have th0:"(n - 1) mod m < m" by blast
  20.749 -      let ?y = "a^ ((n - 1) div m * m)"
  20.750 -      note mdeq = div_mult_mod_eq[of "(n - 1)" m]
  20.751 -      from coprime_exp[OF an(1)[unfolded coprime_commute[of a n]],
  20.752 -        of "(n - 1) div m * m"]
  20.753 -      have yn: "coprime ?y n" by (simp add: coprime_commute)
  20.754 -      have "?y mod n = (a^m)^((n - 1) div m) mod n"
  20.755 -        by (simp add: algebra_simps power_mult)
  20.756 -      also have "\<dots> = (a^m mod n)^((n - 1) div m) mod n"
  20.757 -        using power_mod[of "a^m" n "(n - 1) div m"] by simp
  20.758 -      also have "\<dots> = 1" using m(3)[unfolded modeq_def onen] onen
  20.759 -        by (simp add: power_Suc0)
  20.760 -      finally have th3: "?y mod n = 1"  .
  20.761 -      have th2: "[?y * a ^ ((n - 1) mod m) = ?y* 1] (mod n)"
  20.762 -        using an1[unfolded modeq_def onen] onen
  20.763 -          div_mult_mod_eq[of "(n - 1)" m, symmetric]
  20.764 -        by (simp add:power_add[symmetric] modeq_def th3 del: One_nat_def)
  20.765 -      from cong_mult_lcancel[of ?y n "a^((n - 1) mod m)" 1, OF yn th2]
  20.766 -      have th1: "[a ^ ((n - 1) mod m) = 1] (mod n)"  .
  20.767 -      from m(4)[rule_format, OF th0] nm1
  20.768 -        less_trans[OF mod_less_divisor[OF m(1), of "n - 1"] m(2)] th1
  20.769 -      have False by blast }
  20.770 -    hence "(n - 1) mod m = 0" by auto
  20.771 -    then have mn: "m dvd n - 1" by presburger
  20.772 -    then obtain r where r: "n - 1 = m*r" unfolding dvd_def by blast
  20.773 -    from n01 r m(2) have r01: "r\<noteq>0" "r\<noteq>1" by auto
  20.774 -    from prime_factor[OF r01(2)] obtain p where p: "prime p" "p dvd r" by blast
  20.775 -    hence th: "prime p \<and> p dvd n - 1" unfolding r by (auto intro: dvd_mult)
  20.776 -    have "(a ^ ((n - 1) div p)) mod n = (a^(m*r div p)) mod n" using r
  20.777 -      by (simp add: power_mult)
  20.778 -    also have "\<dots> = (a^(m*(r div p))) mod n" using div_mult1_eq[of m r p] p(2)[unfolded dvd_eq_mod_eq_0] by simp
  20.779 -    also have "\<dots> = ((a^m)^(r div p)) mod n" by (simp add: power_mult)
  20.780 -    also have "\<dots> = ((a^m mod n)^(r div p)) mod n" using power_mod[of "a^m" "n" "r div p" ] ..
  20.781 -    also have "\<dots> = 1" using m(3) onen by (simp add: modeq_def power_Suc0)
  20.782 -    finally have "[(a ^ ((n - 1) div p))= 1] (mod n)"
  20.783 -      using onen by (simp add: modeq_def)
  20.784 -    with pn[rule_format, OF th] have False by blast}
  20.785 -  hence th: "\<forall>m. 0 < m \<and> m < n - 1 \<longrightarrow> \<not> [a ^ m = 1] (mod n)" by blast
  20.786 -  from lucas_weak[OF n2 an1 th] show ?thesis .
  20.787 -qed
  20.788 -
  20.789 -(* Definition of the order of a number mod n (0 in non-coprime case).        *)
  20.790 -
  20.791 -definition "ord n a = (if coprime n a then Least (\<lambda>d. d > 0 \<and> [a ^d = 1] (mod n)) else 0)"
  20.792 -
  20.793 -(* This has the expected properties.                                         *)
  20.794 -
  20.795 -lemma coprime_ord:
  20.796 -  assumes na: "coprime n a"
  20.797 -  shows "ord n a > 0 \<and> [a ^(ord n a) = 1] (mod n) \<and> (\<forall>m. 0 < m \<and> m < ord n a \<longrightarrow> \<not> [a^ m = 1] (mod n))"
  20.798 -proof-
  20.799 -  let ?P = "\<lambda>d. 0 < d \<and> [a ^ d = 1] (mod n)"
  20.800 -  from euclid[of a] obtain p where p: "prime p" "a < p" by blast
  20.801 -  from na have o: "ord n a = Least ?P" by (simp add: ord_def)
  20.802 -  {assume "n=0 \<or> n=1" with na have "\<exists>m>0. ?P m" apply auto apply (rule exI[where x=1]) by (simp  add: modeq_def)}
  20.803 -  moreover
  20.804 -  {assume "n\<noteq>0 \<and> n\<noteq>1" hence n2:"n \<ge> 2" by arith
  20.805 -    from na have na': "coprime a n" by (simp add: coprime_commute)
  20.806 -    have ex: "\<exists>m>0. ?P m"
  20.807 -      by (rule exI[where x="\<phi> n"]) (use phi_lowerbound_1[OF n2] fermat_little[OF na'] in auto) }
  20.808 -  ultimately have ex: "\<exists>m>0. ?P m" by blast
  20.809 -  from nat_exists_least_iff'[of ?P] ex na show ?thesis
  20.810 -    unfolding o[symmetric] by auto
  20.811 -qed
  20.812 -(* With the special value 0 for non-coprime case, it's more convenient.      *)
  20.813 -lemma ord_works:
  20.814 - "[a ^ (ord n a) = 1] (mod n) \<and> (\<forall>m. 0 < m \<and> m < ord n a \<longrightarrow> ~[a^ m = 1] (mod n))"
  20.815 -apply (cases "coprime n a")
  20.816 -using coprime_ord[of n a]
  20.817 -by (blast, simp add: ord_def modeq_def)
  20.818 -
  20.819 -lemma ord: "[a^(ord n a) = 1] (mod n)" using ord_works by blast
  20.820 -lemma ord_minimal: "0 < m \<Longrightarrow> m < ord n a \<Longrightarrow> ~[a^m = 1] (mod n)"
  20.821 -  using ord_works by blast
  20.822 -lemma ord_eq_0: "ord n a = 0 \<longleftrightarrow> ~coprime n a"
  20.823 -by (cases "coprime n a", simp add: coprime_ord, simp add: ord_def)
  20.824 -
  20.825 -lemma ord_divides:
  20.826 - "[a ^ d = 1] (mod n) \<longleftrightarrow> ord n a dvd d" (is "?lhs \<longleftrightarrow> ?rhs")
  20.827 -proof
  20.828 -  assume rh: ?rhs
  20.829 -  then obtain k where "d = ord n a * k" unfolding dvd_def by blast
  20.830 -  hence "[a ^ d = (a ^ (ord n a) mod n)^k] (mod n)"
  20.831 -    by (simp add : modeq_def power_mult power_mod)
  20.832 -  also have "[(a ^ (ord n a) mod n)^k = 1] (mod n)"
  20.833 -    using ord[of a n, unfolded modeq_def]
  20.834 -    by (simp add: modeq_def power_mod power_Suc0)
  20.835 -  finally  show ?lhs .
  20.836 -next
  20.837 -  assume lh: ?lhs
  20.838 -  { assume H: "\<not> coprime n a"
  20.839 -    hence o: "ord n a = 0" by (simp add: ord_def)
  20.840 -    {assume d: "d=0" with o H have ?rhs by (simp add: modeq_def)}
  20.841 -    moreover
  20.842 -    {assume d0: "d\<noteq>0" then obtain d' where d': "d = Suc d'" by (cases d, auto)
  20.843 -      from H[unfolded coprime]
  20.844 -      obtain p where p: "p dvd n" "p dvd a" "p \<noteq> 1" by auto
  20.845 -      from lh[unfolded nat_mod]
  20.846 -      obtain q1 q2 where q12:"a ^ d + n * q1 = 1 + n * q2" by blast
  20.847 -      hence "a ^ d + n * q1 - n * q2 = 1" by simp
  20.848 -      with dvd_diff_nat [OF dvd_add [OF divides_rexp[OF p(2), of d'] dvd_mult2[OF p(1), of q1]] dvd_mult2[OF p(1), of q2]] d' have "p dvd 1" by simp
  20.849 -      with p(3) have False by simp
  20.850 -      hence ?rhs ..}
  20.851 -    ultimately have ?rhs by blast}
  20.852 -  moreover
  20.853 -  {assume H: "coprime n a"
  20.854 -    let ?o = "ord n a"
  20.855 -    let ?q = "d div ord n a"
  20.856 -    let ?r = "d mod ord n a"
  20.857 -    from cong_exp[OF ord[of a n], of ?q]
  20.858 -    have eqo: "[(a^?o)^?q = 1] (mod n)"  by (simp add: modeq_def power_Suc0)
  20.859 -    from H have onz: "?o \<noteq> 0" by (simp add: ord_eq_0)
  20.860 -    hence op: "?o > 0" by simp
  20.861 -    from div_mult_mod_eq[of d "ord n a"] lh
  20.862 -    have "[a^(?o*?q + ?r) = 1] (mod n)" by (simp add: modeq_def mult.commute)
  20.863 -    hence "[(a^?o)^?q * (a^?r) = 1] (mod n)"
  20.864 -      by (simp add: modeq_def power_mult[symmetric] power_add[symmetric])
  20.865 -    hence th: "[a^?r = 1] (mod n)"
  20.866 -      using eqo mod_mult_left_eq[of "(a^?o)^?q" "a^?r" n]
  20.867 -      apply (simp add: modeq_def del: One_nat_def)
  20.868 -      by (simp add: mod_mult_left_eq[symmetric])
  20.869 -    {assume r: "?r = 0" hence ?rhs by (simp add: dvd_eq_mod_eq_0)}
  20.870 -    moreover
  20.871 -    {assume r: "?r \<noteq> 0"
  20.872 -      with mod_less_divisor[OF op, of d] have r0o:"?r >0 \<and> ?r < ?o" by simp
  20.873 -      from conjunct2[OF ord_works[of a n], rule_format, OF r0o] th
  20.874 -      have ?rhs by blast}
  20.875 -    ultimately have ?rhs by blast}
  20.876 -  ultimately  show ?rhs by blast
  20.877 -qed
  20.878 -
  20.879 -lemma order_divides_phi: "coprime n a \<Longrightarrow> ord n a dvd \<phi> n"
  20.880 -using ord_divides fermat_little coprime_commute by simp
  20.881 -lemma order_divides_expdiff:
  20.882 -  assumes na: "coprime n a"
  20.883 -  shows "[a^d = a^e] (mod n) \<longleftrightarrow> [d = e] (mod (ord n a))"
  20.884 -proof-
  20.885 -  {fix n a d e
  20.886 -    assume na: "coprime n a" and ed: "(e::nat) \<le> d"
  20.887 -    hence "\<exists>c. d = e + c" by arith
  20.888 -    then obtain c where c: "d = e + c" by arith
  20.889 -    from na have an: "coprime a n" by (simp add: coprime_commute)
  20.890 -    from coprime_exp[OF na, of e]
  20.891 -    have aen: "coprime (a^e) n" by (simp add: coprime_commute)
  20.892 -    from coprime_exp[OF na, of c]
  20.893 -    have acn: "coprime (a^c) n" by (simp add: coprime_commute)
  20.894 -    have "[a^d = a^e] (mod n) \<longleftrightarrow> [a^(e + c) = a^(e + 0)] (mod n)"
  20.895 -      using c by simp
  20.896 -    also have "\<dots> \<longleftrightarrow> [a^e* a^c = a^e *a^0] (mod n)" by (simp add: power_add)
  20.897 -    also have  "\<dots> \<longleftrightarrow> [a ^ c = 1] (mod n)"
  20.898 -      using cong_mult_lcancel_eq[OF aen, of "a^c" "a^0"] by simp
  20.899 -    also  have "\<dots> \<longleftrightarrow> ord n a dvd c" by (simp only: ord_divides)
  20.900 -    also have "\<dots> \<longleftrightarrow> [e + c = e + 0] (mod ord n a)"
  20.901 -      using cong_add_lcancel_eq[of e c 0 "ord n a", simplified cong_0_divides]
  20.902 -      by simp
  20.903 -    finally have "[a^d = a^e] (mod n) \<longleftrightarrow> [d = e] (mod (ord n a))"
  20.904 -      using c by simp }
  20.905 -  note th = this
  20.906 -  have "e \<le> d \<or> d \<le> e" by arith
  20.907 -  moreover
  20.908 -  {assume ed: "e \<le> d" from th[OF na ed] have ?thesis .}
  20.909 -  moreover
  20.910 -  {assume de: "d \<le> e"
  20.911 -    from th[OF na de] have ?thesis by (simp add: cong_commute) }
  20.912 -  ultimately show ?thesis by blast
  20.913 -qed
  20.914 -
  20.915 -(* Another trivial primality characterization.                               *)
  20.916 -
  20.917 -lemma prime_prime_factor:
  20.918 -  "prime n \<longleftrightarrow> n \<noteq> 1\<and> (\<forall>p. prime p \<and> p dvd n \<longrightarrow> p = n)"
  20.919 -proof-
  20.920 -  {assume n: "n=0 \<or> n=1" hence ?thesis using prime_0 two_is_prime by auto}
  20.921 -  moreover
  20.922 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.923 -    {assume pn: "prime n"
  20.924 -
  20.925 -      from pn[unfolded prime_def] have "\<forall>p. prime p \<and> p dvd n \<longrightarrow> p = n"
  20.926 -        using n
  20.927 -        apply (cases "n = 0 \<or> n=1",simp)
  20.928 -        by (clarsimp, erule_tac x="p" in allE, auto)}
  20.929 -    moreover
  20.930 -    {assume H: "\<forall>p. prime p \<and> p dvd n \<longrightarrow> p = n"
  20.931 -      from n have n1: "n > 1" by arith
  20.932 -      {fix m assume m: "m dvd n" "m\<noteq>1"
  20.933 -        from prime_factor[OF m(2)] obtain p where
  20.934 -          p: "prime p" "p dvd m" by blast
  20.935 -        from dvd_trans[OF p(2) m(1)] p(1) H have "p = n" by blast
  20.936 -        with p(2) have "n dvd m"  by simp
  20.937 -        hence "m=n"  using dvd_antisym[OF m(1)] by simp }
  20.938 -      with n1 have "prime n"  unfolding prime_def by auto }
  20.939 -    ultimately have ?thesis using n by blast}
  20.940 -  ultimately       show ?thesis by auto
  20.941 -qed
  20.942 -
  20.943 -lemma prime_divisor_sqrt:
  20.944 -  "prime n \<longleftrightarrow> n \<noteq> 1 \<and> (\<forall>d. d dvd n \<and> d\<^sup>2 \<le> n \<longrightarrow> d = 1)"
  20.945 -proof-
  20.946 -  {assume "n=0 \<or> n=1" hence ?thesis using prime_0 prime_1
  20.947 -    by (auto simp add: nat_power_eq_0_iff)}
  20.948 -  moreover
  20.949 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.950 -    hence np: "n > 1" by arith
  20.951 -    {fix d assume d: "d dvd n" "d\<^sup>2 \<le> n" and H: "\<forall>m. m dvd n \<longrightarrow> m=1 \<or> m=n"
  20.952 -      from H d have d1n: "d = 1 \<or> d=n" by blast
  20.953 -      {assume dn: "d=n"
  20.954 -        have "n\<^sup>2 > n*1" using n by (simp add: power2_eq_square)
  20.955 -        with dn d(2) have "d=1" by simp}
  20.956 -      with d1n have "d = 1" by blast  }
  20.957 -    moreover
  20.958 -    {fix d assume d: "d dvd n" and H: "\<forall>d'. d' dvd n \<and> d'\<^sup>2 \<le> n \<longrightarrow> d' = 1"
  20.959 -      from d n have "d \<noteq> 0" apply - apply (rule ccontr) by simp
  20.960 -      hence dp: "d > 0" by simp
  20.961 -      from d[unfolded dvd_def] obtain e where e: "n= d*e" by blast
  20.962 -      from n dp e have ep:"e > 0" by simp
  20.963 -      have "d\<^sup>2 \<le> n \<or> e\<^sup>2 \<le> n" using dp ep
  20.964 -        by (auto simp add: e power2_eq_square mult_le_cancel_left)
  20.965 -      moreover
  20.966 -      {assume h: "d\<^sup>2 \<le> n"
  20.967 -        from H[rule_format, of d] h d have "d = 1" by blast}
  20.968 -      moreover
  20.969 -      {assume h: "e\<^sup>2 \<le> n"
  20.970 -        from e have "e dvd n" unfolding dvd_def by (simp add: mult.commute)
  20.971 -        with H[rule_format, of e] h have "e=1" by simp
  20.972 -        with e have "d = n" by simp}
  20.973 -      ultimately have "d=1 \<or> d=n"  by blast}
  20.974 -    ultimately have ?thesis unfolding prime_def using np n(2) by blast}
  20.975 -  ultimately show ?thesis by auto
  20.976 -qed
  20.977 -lemma prime_prime_factor_sqrt:
  20.978 -  "prime n \<longleftrightarrow> n \<noteq> 0 \<and> n \<noteq> 1 \<and> \<not> (\<exists>p. prime p \<and> p dvd n \<and> p\<^sup>2 \<le> n)"
  20.979 -  (is "?lhs \<longleftrightarrow>?rhs")
  20.980 -proof-
  20.981 -  {assume "n=0 \<or> n=1" hence ?thesis using prime_0 prime_1 by auto}
  20.982 -  moreover
  20.983 -  {assume n: "n\<noteq>0" "n\<noteq>1"
  20.984 -    {assume H: ?lhs
  20.985 -      from H[unfolded prime_divisor_sqrt] n
  20.986 -      have ?rhs
  20.987 -        apply clarsimp
  20.988 -        apply (erule_tac x="p" in allE)
  20.989 -        apply simp
  20.990 -        done
  20.991 -    }
  20.992 -    moreover
  20.993 -    {assume H: ?rhs
  20.994 -      {fix d assume d: "d dvd n" "d\<^sup>2 \<le> n" "d\<noteq>1"
  20.995 -        from prime_factor[OF d(3)]
  20.996 -        obtain p where p: "prime p" "p dvd d" by blast
  20.997 -        from n have np: "n > 0" by arith
  20.998 -        have "d \<noteq> 0" by (rule ccontr) (use d(1) n in auto)
  20.999 -        hence dp: "d > 0" by arith
 20.1000 -        from mult_mono[OF dvd_imp_le[OF p(2) dp] dvd_imp_le[OF p(2) dp]] d(2)
 20.1001 -        have "p\<^sup>2 \<le> n" unfolding power2_eq_square by arith
 20.1002 -        with H n p(1) dvd_trans[OF p(2) d(1)] have False  by blast}
 20.1003 -      with n prime_divisor_sqrt  have ?lhs by auto}
 20.1004 -    ultimately have ?thesis by blast }
 20.1005 -  ultimately show ?thesis by (cases "n=0 \<or> n=1", auto)
 20.1006 -qed
 20.1007 -(* Pocklington theorem. *)
 20.1008 -
 20.1009 -lemma pocklington_lemma:
 20.1010 -  assumes n: "n \<ge> 2" and nqr: "n - 1 = q*r" and an: "[a^ (n - 1) = 1] (mod n)"
 20.1011 -  and aq:"\<forall>p. prime p \<and> p dvd q \<longrightarrow> coprime (a^ ((n - 1) div p) - 1) n"
 20.1012 -  and pp: "prime p" and pn: "p dvd n"
 20.1013 -  shows "[p = 1] (mod q)"
 20.1014 -proof-
 20.1015 -  from pp prime_0 prime_1 have p01: "p \<noteq> 0" "p \<noteq> 1" by - (rule ccontr, simp)+
 20.1016 -  from cong_1_divides[OF an, unfolded nqr, unfolded dvd_def]
 20.1017 -  obtain k where k: "a ^ (q * r) - 1 = n*k" by blast
 20.1018 -  from pn[unfolded dvd_def] obtain l where l: "n = p*l" by blast
 20.1019 -  {assume a0: "a = 0"
 20.1020 -    hence "a^ (n - 1) = 0" using n by (simp add: power_0_left)
 20.1021 -    with n an mod_less[of 1 n]  have False by (simp add: power_0_left modeq_def)}
 20.1022 -  hence a0: "a\<noteq>0" ..
 20.1023 -  from n nqr have aqr0: "a ^ (q * r) \<noteq> 0" using a0 by simp
 20.1024 -  hence "(a ^ (q * r) - 1) + 1  = a ^ (q * r)" by simp
 20.1025 -  with k l have "a ^ (q * r) = p*l*k + 1" by simp
 20.1026 -  hence "a ^ (r * q) + p * 0 = 1 + p * (l*k)" by (simp add: ac_simps)
 20.1027 -  hence odq: "ord p (a^r) dvd q"
 20.1028 -    unfolding ord_divides[symmetric] power_mult[symmetric] nat_mod  by blast
 20.1029 -  from odq[unfolded dvd_def] obtain d where d: "q = ord p (a^r) * d" by blast
 20.1030 -  {assume d1: "d \<noteq> 1"
 20.1031 -    from prime_factor[OF d1] obtain P where P: "prime P" "P dvd d" by blast
 20.1032 -    from d dvd_mult[OF P(2), of "ord p (a^r)"] have Pq: "P dvd q" by simp
 20.1033 -    from aq P(1) Pq have caP:"coprime (a^ ((n - 1) div P) - 1) n" by blast
 20.1034 -    from Pq obtain s where s: "q = P*s" unfolding dvd_def by blast
 20.1035 -    have P0: "P \<noteq> 0" by (rule ccontr) (use P(1) prime_0 in simp)
 20.1036 -    from P(2) obtain t where t: "d = P*t" unfolding dvd_def by blast
 20.1037 -    from d s t P0  have s': "ord p (a^r) * t = s" by algebra
 20.1038 -    have "ord p (a^r) * t*r = r * ord p (a^r) * t" by algebra
 20.1039 -    hence exps: "a^(ord p (a^r) * t*r) = ((a ^ r) ^ ord p (a^r)) ^ t"
 20.1040 -      by (simp only: power_mult)
 20.1041 -    have "[((a ^ r) ^ ord p (a^r)) ^ t= 1^t] (mod p)"
 20.1042 -      by (rule cong_exp, rule ord)
 20.1043 -    then have th: "[((a ^ r) ^ ord p (a^r)) ^ t= 1] (mod p)"
 20.1044 -      by (simp add: power_Suc0)
 20.1045 -    from cong_1_divides[OF th] exps have pd0: "p dvd a^(ord p (a^r) * t*r) - 1" by simp
 20.1046 -    from nqr s s' have "(n - 1) div P = ord p (a^r) * t*r" using P0 by simp
 20.1047 -    with caP have "coprime (a^(ord p (a^r) * t*r) - 1) n" by simp
 20.1048 -    with p01 pn pd0 have False unfolding coprime by auto}
 20.1049 -  hence d1: "d = 1" by blast
 20.1050 -  hence o: "ord p (a^r) = q" using d by simp
 20.1051 -  from pp phi_prime[of p] have phip: " \<phi> p = p - 1" by simp
 20.1052 -  {fix d assume d: "d dvd p" "d dvd a" "d \<noteq> 1"
 20.1053 -    from pp[unfolded prime_def] d have dp: "d = p" by blast
 20.1054 -    from n have n12:"Suc (n - 2) = n - 1" by arith
 20.1055 -    with divides_rexp[OF d(2)[unfolded dp], of "n - 2"]
 20.1056 -    have th0: "p dvd a ^ (n - 1)" by simp
 20.1057 -    from n have n0: "n \<noteq> 0" by simp
 20.1058 -    have a0: "a \<noteq> 0"
 20.1059 -      by (rule ccontr) (use d(2) an n12[symmetric] in \<open>simp add: modeq_def\<close>)
 20.1060 -    have th1: "a^ (n - 1) \<noteq> 0" using n d(2) dp a0 by auto
 20.1061 -    from coprime_minus1[OF th1, unfolded coprime]
 20.1062 -      dvd_trans[OF pn cong_1_divides[OF an]] th0 d(3) dp
 20.1063 -    have False by auto}
 20.1064 -  hence cpa: "coprime p a" using coprime by auto
 20.1065 -  from coprime_exp[OF cpa, of r] coprime_commute
 20.1066 -  have arp: "coprime (a^r) p" by blast
 20.1067 -  from fermat_little[OF arp, simplified ord_divides] o phip
 20.1068 -  have "q dvd (p - 1)" by simp
 20.1069 -  then obtain d where d:"p - 1 = q * d" unfolding dvd_def by blast
 20.1070 -  have p0: "p \<noteq> 0" by (rule ccontr) (use prime_0 pp in auto)
 20.1071 -  from p0 d have "p + q * 0 = 1 + q * d" by simp
 20.1072 -  with nat_mod[of p 1 q, symmetric]
 20.1073 -  show ?thesis by blast
 20.1074 -qed
 20.1075 -
 20.1076 -lemma pocklington:
 20.1077 -  assumes n: "n \<ge> 2" and nqr: "n - 1 = q*r" and sqr: "n \<le> q\<^sup>2"
 20.1078 -  and an: "[a^ (n - 1) = 1] (mod n)"
 20.1079 -  and aq:"\<forall>p. prime p \<and> p dvd q \<longrightarrow> coprime (a^ ((n - 1) div p) - 1) n"
 20.1080 -  shows "prime n"
 20.1081 -unfolding prime_prime_factor_sqrt[of n]
 20.1082 -proof-
 20.1083 -  let ?ths = "n \<noteq> 0 \<and> n \<noteq> 1 \<and> \<not> (\<exists>p. prime p \<and> p dvd n \<and> p\<^sup>2 \<le> n)"
 20.1084 -  from n have n01: "n\<noteq>0" "n\<noteq>1" by arith+
 20.1085 -  {fix p assume p: "prime p" "p dvd n" "p\<^sup>2 \<le> n"
 20.1086 -    from p(3) sqr have "p^(Suc 1) \<le> q^(Suc 1)" by (simp add: power2_eq_square)
 20.1087 -    hence pq: "p \<le> q" unfolding exp_mono_le .
 20.1088 -    from pocklington_lemma[OF n nqr an aq p(1,2)]  cong_1_divides
 20.1089 -    have th: "q dvd p - 1" by blast
 20.1090 -    have "p - 1 \<noteq> 0"using prime_ge_2[OF p(1)] by arith
 20.1091 -    with divides_ge[OF th] pq have False by arith }
 20.1092 -  with n01 show ?ths by blast
 20.1093 -qed
 20.1094 -
 20.1095 -(* Variant for application, to separate the exponentiation.                  *)
 20.1096 -lemma pocklington_alt:
 20.1097 -  assumes n: "n \<ge> 2" and nqr: "n - 1 = q*r" and sqr: "n \<le> q\<^sup>2"
 20.1098 -  and an: "[a^ (n - 1) = 1] (mod n)"
 20.1099 -  and aq:"\<forall>p. prime p \<and> p dvd q \<longrightarrow> (\<exists>b. [a^((n - 1) div p) = b] (mod n) \<and> coprime (b - 1) n)"
 20.1100 -  shows "prime n"
 20.1101 -proof-
 20.1102 -  {fix p assume p: "prime p" "p dvd q"
 20.1103 -    from aq[rule_format] p obtain b where
 20.1104 -      b: "[a^((n - 1) div p) = b] (mod n)" "coprime (b - 1) n" by blast
 20.1105 -    {assume a0: "a=0"
 20.1106 -      from n an have "[0 = 1] (mod n)" unfolding a0 power_0_left by auto
 20.1107 -      hence False using n by (simp add: modeq_def dvd_eq_mod_eq_0[symmetric])}
 20.1108 -    hence a0: "a\<noteq> 0" ..
 20.1109 -    hence a1: "a \<ge> 1" by arith
 20.1110 -    from one_le_power[OF a1] have ath: "1 \<le> a ^ ((n - 1) div p)" .
 20.1111 -    {assume b0: "b = 0"
 20.1112 -      from p(2) nqr have "(n - 1) mod p = 0"
 20.1113 -        apply (simp only: dvd_eq_mod_eq_0[symmetric]) by (rule dvd_mult2, simp)
 20.1114 -      with div_mult_mod_eq[of "n - 1" p]
 20.1115 -      have "(n - 1) div p * p= n - 1" by auto
 20.1116 -      hence eq: "(a^((n - 1) div p))^p = a^(n - 1)"
 20.1117 -        by (simp only: power_mult[symmetric])
 20.1118 -      from prime_ge_2[OF p(1)] have pS: "Suc (p - 1) = p" by arith
 20.1119 -      from b(1) have d: "n dvd a^((n - 1) div p)" unfolding b0 cong_0_divides .
 20.1120 -      from divides_rexp[OF d, of "p - 1"] pS eq cong_divides[OF an] n
 20.1121 -      have False by simp}
 20.1122 -    then have b0: "b \<noteq> 0" ..
 20.1123 -    hence b1: "b \<ge> 1" by arith
 20.1124 -    from cong_coprime[OF cong_sub[OF b(1) cong_refl[of 1] ath b1]] b(2) nqr
 20.1125 -    have "coprime (a ^ ((n - 1) div p) - 1) n" by (simp add: coprime_commute)}
 20.1126 -  hence th: "\<forall>p. prime p \<and> p dvd q \<longrightarrow> coprime (a ^ ((n - 1) div p) - 1) n "
 20.1127 -    by blast
 20.1128 -  from pocklington[OF n nqr sqr an th] show ?thesis .
 20.1129 -qed
 20.1130 -
 20.1131 -(* Prime factorizations.                                                     *)
 20.1132 -
 20.1133 -definition "primefact ps n = (foldr op * ps  1 = n \<and> (\<forall>p\<in> set ps. prime p))"
 20.1134 -
 20.1135 -lemma primefact: assumes n: "n \<noteq> 0"
 20.1136 -  shows "\<exists>ps. primefact ps n"
 20.1137 -using n
 20.1138 -proof(induct n rule: nat_less_induct)
 20.1139 -  fix n assume H: "\<forall>m<n. m \<noteq> 0 \<longrightarrow> (\<exists>ps. primefact ps m)" and n: "n\<noteq>0"
 20.1140 -  let ?ths = "\<exists>ps. primefact ps n"
 20.1141 -  {assume "n = 1"
 20.1142 -    hence "primefact [] n" by (simp add: primefact_def)
 20.1143 -    hence ?ths by blast }
 20.1144 -  moreover
 20.1145 -  {assume n1: "n \<noteq> 1"
 20.1146 -    with n have n2: "n \<ge> 2" by arith
 20.1147 -    from prime_factor[OF n1] obtain p where p: "prime p" "p dvd n" by blast
 20.1148 -    from p(2) obtain m where m: "n = p*m" unfolding dvd_def by blast
 20.1149 -    from n m have m0: "m > 0" "m\<noteq>0" by auto
 20.1150 -    from prime_ge_2[OF p(1)] have "1 < p" by arith
 20.1151 -    with m0 m have mn: "m < n" by auto
 20.1152 -    from H[rule_format, OF mn m0(2)] obtain ps where ps: "primefact ps m" ..
 20.1153 -    from ps m p(1) have "primefact (p#ps) n" by (simp add: primefact_def)
 20.1154 -    hence ?ths by blast}
 20.1155 -  ultimately show ?ths by blast
 20.1156 -qed
 20.1157 -
 20.1158 -lemma primefact_contains:
 20.1159 -  assumes pf: "primefact ps n" and p: "prime p" and pn: "p dvd n"
 20.1160 -  shows "p \<in> set ps"
 20.1161 -  using pf p pn
 20.1162 -proof(induct ps arbitrary: p n)
 20.1163 -  case Nil thus ?case by (auto simp add: primefact_def)
 20.1164 -next
 20.1165 -  case (Cons q qs p n)
 20.1166 -  from Cons.prems[unfolded primefact_def]
 20.1167 -  have q: "prime q" "q * foldr op * qs 1 = n" "\<forall>p \<in>set qs. prime p"  and p: "prime p" "p dvd q * foldr op * qs 1" by simp_all
 20.1168 -  {assume "p dvd q"
 20.1169 -    with p(1) q(1) have "p = q" unfolding prime_def by auto
 20.1170 -    hence ?case by simp}
 20.1171 -  moreover
 20.1172 -  { assume h: "p dvd foldr op * qs 1"
 20.1173 -    from q(3) have pqs: "primefact qs (foldr op * qs 1)"
 20.1174 -      by (simp add: primefact_def)
 20.1175 -    from Cons.hyps[OF pqs p(1) h] have ?case by simp}
 20.1176 -  ultimately show ?case using prime_divprod[OF p] by blast
 20.1177 -qed
 20.1178 -
 20.1179 -lemma primefact_variant: "primefact ps n \<longleftrightarrow> foldr op * ps 1 = n \<and> list_all prime ps"
 20.1180 -  by (auto simp add: primefact_def list_all_iff)
 20.1181 -
 20.1182 -(* Variant of Lucas theorem.                                                 *)
 20.1183 -
 20.1184 -lemma lucas_primefact:
 20.1185 -  assumes n: "n \<ge> 2" and an: "[a^(n - 1) = 1] (mod n)"
 20.1186 -  and psn: "foldr op * ps 1 = n - 1"
 20.1187 -  and psp: "list_all (\<lambda>p. prime p \<and> \<not> [a^((n - 1) div p) = 1] (mod n)) ps"
 20.1188 -  shows "prime n"
 20.1189 -proof-
 20.1190 -  {fix p assume p: "prime p" "p dvd n - 1" "[a ^ ((n - 1) div p) = 1] (mod n)"
 20.1191 -    from psn psp have psn1: "primefact ps (n - 1)"
 20.1192 -      by (auto simp add: list_all_iff primefact_variant)
 20.1193 -    from p(3) primefact_contains[OF psn1 p(1,2)] psp
 20.1194 -    have False by (induct ps, auto)}
 20.1195 -  with lucas[OF n an] show ?thesis by blast
 20.1196 -qed
 20.1197 -
 20.1198 -(* Variant of Pocklington theorem.                                           *)
 20.1199 -
 20.1200 -lemma mod_le: assumes n: "n \<noteq> (0::nat)" shows "m mod n \<le> m"
 20.1201 -proof-
 20.1202 -    from div_mult_mod_eq[of m n]
 20.1203 -    have "\<exists>x. x + m mod n = m" by blast
 20.1204 -    then show ?thesis by auto
 20.1205 -qed
 20.1206 -
 20.1207 -
 20.1208 -lemma pocklington_primefact:
 20.1209 -  assumes n: "n \<ge> 2" and qrn: "q*r = n - 1" and nq2: "n \<le> q\<^sup>2"
 20.1210 -  and arnb: "(a^r) mod n = b" and psq: "foldr op * ps 1 = q"
 20.1211 -  and bqn: "(b^q) mod n = 1"
 20.1212 -  and psp: "list_all (\<lambda>p. prime p \<and> coprime ((b^(q div p)) mod n - 1) n) ps"
 20.1213 -  shows "prime n"
 20.1214 -proof-
 20.1215 -  from bqn psp qrn
 20.1216 -  have bqn: "a ^ (n - 1) mod n = 1"
 20.1217 -    and psp: "list_all (\<lambda>p. prime p \<and> coprime (a^(r *(q div p)) mod n - 1) n) ps"  unfolding arnb[symmetric] power_mod
 20.1218 -    by (simp_all add: power_mult[symmetric] algebra_simps)
 20.1219 -  from n  have n0: "n > 0" by arith
 20.1220 -  from div_mult_mod_eq[of "a^(n - 1)" n]
 20.1221 -    mod_less_divisor[OF n0, of "a^(n - 1)"]
 20.1222 -  have an1: "[a ^ (n - 1) = 1] (mod n)"
 20.1223 -    unfolding nat_mod bqn
 20.1224 -    apply -
 20.1225 -    apply (rule exI[where x="0"])
 20.1226 -    apply (rule exI[where x="a^(n - 1) div n"])
 20.1227 -    by (simp add: algebra_simps)
 20.1228 -  {fix p assume p: "prime p" "p dvd q"
 20.1229 -    from psp psq have pfpsq: "primefact ps q"
 20.1230 -      by (auto simp add: primefact_variant list_all_iff)
 20.1231 -    from psp primefact_contains[OF pfpsq p]
 20.1232 -    have p': "coprime (a ^ (r * (q div p)) mod n - 1) n"
 20.1233 -      by (simp add: list_all_iff)
 20.1234 -    from prime_ge_2[OF p(1)] have p01: "p \<noteq> 0" "p \<noteq> 1" "p =Suc(p - 1)" by arith+
 20.1235 -    from div_mult1_eq[of r q p] p(2)
 20.1236 -    have eq1: "r* (q div p) = (n - 1) div p"
 20.1237 -      unfolding qrn[symmetric] dvd_eq_mod_eq_0 by (simp add: mult.commute)
 20.1238 -    have ath: "\<And>a (b::nat). a <= b \<Longrightarrow> a \<noteq> 0 ==> 1 <= a \<and> 1 <= b" by arith
 20.1239 -    from n0 have n00: "n \<noteq> 0" by arith
 20.1240 -    from mod_le[OF n00]
 20.1241 -    have th10: "a ^ ((n - 1) div p) mod n \<le> a ^ ((n - 1) div p)" .
 20.1242 -    {assume "a ^ ((n - 1) div p) mod n = 0"
 20.1243 -      then obtain s where s: "a ^ ((n - 1) div p) = n*s"
 20.1244 -        unfolding mod_eq_0_iff by blast
 20.1245 -      hence eq0: "(a^((n - 1) div p))^p = (n*s)^p" by simp
 20.1246 -      from qrn[symmetric] have qn1: "q dvd n - 1" unfolding dvd_def by auto
 20.1247 -      with p(2) have npp: "(n - 1) div p * p = n - 1"
 20.1248 -        by (auto intro: dvd_div_mult_self dvd_trans)
 20.1249 -      with eq0 have "a^ (n - 1) = (n*s)^p"
 20.1250 -        by (simp add: power_mult[symmetric])
 20.1251 -      hence "1 = (n*s)^(Suc (p - 1)) mod n" using bqn p01 by simp
 20.1252 -      also have "\<dots> = 0" by (simp add: mult.assoc)
 20.1253 -      finally have False by simp }
 20.1254 -      then have th11: "a ^ ((n - 1) div p) mod n \<noteq> 0" by auto
 20.1255 -    have th1: "[a ^ ((n - 1) div p) mod n = a ^ ((n - 1) div p)] (mod n)"
 20.1256 -      unfolding modeq_def by simp
 20.1257 -    from cong_sub[OF th1 cong_refl[of 1]]  ath[OF th10 th11]
 20.1258 -    have th: "[a ^ ((n - 1) div p) mod n - 1 = a ^ ((n - 1) div p) - 1] (mod n)"
 20.1259 -      by blast
 20.1260 -    from cong_coprime[OF th] p'[unfolded eq1]
 20.1261 -    have "coprime (a ^ ((n - 1) div p) - 1) n" by (simp add: coprime_commute) }
 20.1262 -  with pocklington[OF n qrn[symmetric] nq2 an1]
 20.1263 -  show ?thesis by blast
 20.1264 -qed
 20.1265 -
 20.1266 -end
    21.1 --- a/src/HOL/Old_Number_Theory/Primes.thy	Tue Oct 18 07:04:08 2016 +0200
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,840 +0,0 @@
    21.4 -(*  Title:      HOL/Old_Number_Theory/Primes.thy
    21.5 -    Author:     Amine Chaieb, Christophe Tabacznyj and Lawrence C Paulson
    21.6 -    Copyright   1996  University of Cambridge
    21.7 -*)
    21.8 -
    21.9 -section \<open>Primality on nat\<close>
   21.10 -
   21.11 -theory Primes
   21.12 -imports Complex_Main Legacy_GCD
   21.13 -begin
   21.14 -
   21.15 -definition coprime :: "nat => nat => bool"
   21.16 -  where "coprime m n \<longleftrightarrow> gcd m n = 1"
   21.17 -
   21.18 -definition prime :: "nat \<Rightarrow> bool"
   21.19 -  where "prime p \<longleftrightarrow> (1 < p \<and> (\<forall>m. m dvd p --> m = 1 \<or> m = p))"
   21.20 -
   21.21 -
   21.22 -lemma two_is_prime: "prime 2"
   21.23 -  apply (auto simp add: prime_def)
   21.24 -  apply (case_tac m)
   21.25 -   apply (auto dest!: dvd_imp_le)
   21.26 -  done
   21.27 -
   21.28 -lemma prime_imp_relprime: "prime p ==> \<not> p dvd n ==> gcd p n = 1"
   21.29 -  apply (auto simp add: prime_def)
   21.30 -  apply (metis gcd_dvd1 gcd_dvd2)
   21.31 -  done
   21.32 -
   21.33 -text \<open>
   21.34 -  This theorem leads immediately to a proof of the uniqueness of
   21.35 -  factorization.  If @{term p} divides a product of primes then it is
   21.36 -  one of those primes.
   21.37 -\<close>
   21.38 -
   21.39 -lemma prime_dvd_mult: "prime p ==> p dvd m * n ==> p dvd m \<or> p dvd n"
   21.40 -  by (blast intro: relprime_dvd_mult prime_imp_relprime)
   21.41 -
   21.42 -lemma prime_dvd_square: "prime p ==> p dvd m^Suc (Suc 0) ==> p dvd m"
   21.43 -  by (auto dest: prime_dvd_mult)
   21.44 -
   21.45 -lemma prime_dvd_power_two: "prime p ==> p dvd m\<^sup>2 ==> p dvd m"
   21.46 -  by (rule prime_dvd_square) (simp_all add: power2_eq_square)
   21.47 -
   21.48 -
   21.49 -lemma exp_eq_1:"(x::nat)^n = 1 \<longleftrightarrow> x = 1 \<or> n = 0"
   21.50 -by (induct n, auto)
   21.51 -
   21.52 -lemma exp_mono_lt: "(x::nat) ^ (Suc n) < y ^ (Suc n) \<longleftrightarrow> x < y"
   21.53 -by(metis linorder_not_less not_less0 power_le_imp_le_base power_less_imp_less_base)
   21.54 -
   21.55 -lemma exp_mono_le: "(x::nat) ^ (Suc n) \<le> y ^ (Suc n) \<longleftrightarrow> x \<le> y"
   21.56 -by (simp only: linorder_not_less[symmetric] exp_mono_lt)
   21.57 -
   21.58 -lemma exp_mono_eq: "(x::nat) ^ Suc n = y ^ Suc n \<longleftrightarrow> x = y"
   21.59 -using power_inject_base[of x n y] by auto
   21.60 -
   21.61 -
   21.62 -lemma even_square: assumes e: "even (n::nat)" shows "\<exists>x. n\<^sup>2 = 4*x"
   21.63 -proof-
   21.64 -  from e have "2 dvd n" by presburger
   21.65 -  then obtain k where k: "n = 2*k" using dvd_def by auto
   21.66 -  hence "n\<^sup>2 = 4 * k\<^sup>2" by (simp add: power2_eq_square)
   21.67 -  thus ?thesis by blast
   21.68 -qed
   21.69 -
   21.70 -lemma odd_square: assumes e: "odd (n::nat)" shows "\<exists>x. n\<^sup>2 = 4*x + 1"
   21.71 -proof-
   21.72 -  from e have np: "n > 0" by presburger
   21.73 -  from e have "2 dvd (n - 1)" by presburger
   21.74 -  then obtain k where "n - 1 = 2 * k" ..
   21.75 -  hence k: "n = 2*k + 1"  using e by presburger 
   21.76 -  hence "n\<^sup>2 = 4* (k\<^sup>2 + k) + 1" by algebra   
   21.77 -  thus ?thesis by blast
   21.78 -qed
   21.79 -
   21.80 -lemma diff_square: "(x::nat)\<^sup>2 - y\<^sup>2 = (x+y)*(x - y)" 
   21.81 -proof-
   21.82 -  have "x \<le> y \<or> y \<le> x" by (rule nat_le_linear)
   21.83 -  moreover
   21.84 -  {assume le: "x \<le> y"
   21.85 -    hence "x\<^sup>2 \<le> y\<^sup>2" by (simp only: numeral_2_eq_2 exp_mono_le Let_def)
   21.86 -    with le have ?thesis by simp }
   21.87 -  moreover
   21.88 -  {assume le: "y \<le> x"
   21.89 -    hence le2: "y\<^sup>2 \<le> x\<^sup>2" by (simp only: numeral_2_eq_2 exp_mono_le Let_def)
   21.90 -    from le have "\<exists>z. y + z = x" by presburger
   21.91 -    then obtain z where z: "x = y + z" by blast 
   21.92 -    from le2 have "\<exists>z. x\<^sup>2 = y\<^sup>2 + z" by presburger
   21.93 -    then obtain z2 where z2: "x\<^sup>2 = y\<^sup>2 + z2" by blast
   21.94 -    from z z2 have ?thesis by simp algebra }
   21.95 -  ultimately show ?thesis by blast  
   21.96 -qed
   21.97 -
   21.98 -text \<open>Elementary theory of divisibility\<close>
   21.99 -lemma divides_ge: "(a::nat) dvd b \<Longrightarrow> b = 0 \<or> a \<le> b" unfolding dvd_def by auto
  21.100 -lemma divides_antisym: "(x::nat) dvd y \<and> y dvd x \<longleftrightarrow> x = y"
  21.101 -  using dvd_antisym[of x y] by auto
  21.102 -
  21.103 -lemma divides_add_revr: assumes da: "(d::nat) dvd a" and dab:"d dvd (a + b)"
  21.104 -  shows "d dvd b"
  21.105 -proof-
  21.106 -  from da obtain k where k:"a = d*k" by (auto simp add: dvd_def)
  21.107 -  from dab obtain k' where k': "a + b = d*k'" by (auto simp add: dvd_def)
  21.108 -  from k k' have "b = d *(k' - k)" by (simp add : diff_mult_distrib2)
  21.109 -  thus ?thesis unfolding dvd_def by blast
  21.110 -qed
  21.111 -
  21.112 -declare nat_mult_dvd_cancel_disj[presburger]
  21.113 -lemma nat_mult_dvd_cancel_disj'[presburger]: 
  21.114 -  "(m::nat)*k dvd n*k \<longleftrightarrow> k = 0 \<or> m dvd n" unfolding mult.commute[of m k] mult.commute[of n k] by presburger 
  21.115 -
  21.116 -lemma divides_mul_l: "(a::nat) dvd b ==> (c * a) dvd (c * b)"
  21.117 -  by presburger
  21.118 -
  21.119 -lemma divides_mul_r: "(a::nat) dvd b ==> (a * c) dvd (b * c)" by presburger
  21.120 -lemma divides_cases: "(n::nat) dvd m ==> m = 0 \<or> m = n \<or> 2 * n <= m" 
  21.121 -  by (auto simp add: dvd_def)
  21.122 -
  21.123 -lemma divides_div_not: "(x::nat) = (q * n) + r \<Longrightarrow> 0 < r \<Longrightarrow> r < n ==> ~(n dvd x)"
  21.124 -proof(auto simp add: dvd_def)
  21.125 -  fix k assume H: "0 < r" "r < n" "q * n + r = n * k"
  21.126 -  from H(3) have r: "r = n* (k -q)" by(simp add: diff_mult_distrib2 mult.commute)
  21.127 -  {assume "k - q = 0" with r H(1) have False by simp}
  21.128 -  moreover
  21.129 -  {assume "k - q \<noteq> 0" with r have "r \<ge> n" by auto
  21.130 -    with H(2) have False by simp}
  21.131 -  ultimately show False by blast
  21.132 -qed
  21.133 -lemma divides_exp: "(x::nat) dvd y ==> x ^ n dvd y ^ n"
  21.134 -  by (auto simp add: power_mult_distrib dvd_def)
  21.135 -
  21.136 -lemma divides_exp2: "n \<noteq> 0 \<Longrightarrow> (x::nat) ^ n dvd y \<Longrightarrow> x dvd y" 
  21.137 -  by (induct n ,auto simp add: dvd_def)
  21.138 -
  21.139 -fun fact :: "nat \<Rightarrow> nat" where
  21.140 -  "fact 0 = 1"
  21.141 -| "fact (Suc n) = Suc n * fact n"
  21.142 -
  21.143 -lemma fact_lt: "0 < fact n" by(induct n, simp_all)
  21.144 -lemma fact_le: "fact n \<ge> 1" using fact_lt[of n] by simp 
  21.145 -lemma fact_mono: assumes le: "m \<le> n" shows "fact m \<le> fact n"
  21.146 -proof-
  21.147 -  from le have "\<exists>i. n = m+i" by presburger
  21.148 -  then obtain i where i: "n = m+i" by blast 
  21.149 -  have "fact m \<le> fact (m + i)"
  21.150 -  proof(induct m)
  21.151 -    case 0 thus ?case using fact_le[of i] by simp
  21.152 -  next
  21.153 -    case (Suc m)
  21.154 -    have "fact (Suc m) = Suc m * fact m" by simp
  21.155 -    have th1: "Suc m \<le> Suc (m + i)" by simp
  21.156 -    from mult_le_mono[of "Suc m" "Suc (m+i)" "fact m" "fact (m+i)", OF th1 Suc.hyps]
  21.157 -    show ?case by simp
  21.158 -  qed
  21.159 -  thus ?thesis using i by simp
  21.160 -qed
  21.161 -
  21.162 -lemma divides_fact: "1 <= p \<Longrightarrow> p <= n ==> p dvd fact n"
  21.163 -proof(induct n arbitrary: p)
  21.164 -  case 0 thus ?case by simp
  21.165 -next
  21.166 -  case (Suc n p)
  21.167 -  from Suc.prems have "p = Suc n \<or> p \<le> n" by presburger 
  21.168 -  moreover
  21.169 -  {assume "p = Suc n" hence ?case  by (simp only: fact.simps dvd_triv_left)}
  21.170 -  moreover
  21.171 -  {assume "p \<le> n"
  21.172 -    with Suc.prems(1) Suc.hyps have th: "p dvd fact n" by simp
  21.173 -    from dvd_mult[OF th] have ?case by (simp only: fact.simps) }
  21.174 -  ultimately show ?case by blast
  21.175 -qed
  21.176 -
  21.177 -declare dvd_triv_left[presburger]
  21.178 -declare dvd_triv_right[presburger]
  21.179 -lemma divides_rexp: 
  21.180 -  "x dvd y \<Longrightarrow> (x::nat) dvd (y^(Suc n))" by (simp add: dvd_mult2[of x y])
  21.181 -
  21.182 -text \<open>Coprimality\<close>
  21.183 -
  21.184 -lemma coprime: "coprime a b \<longleftrightarrow> (\<forall>d. d dvd a \<and> d dvd b \<longleftrightarrow> d = 1)"
  21.185 -using gcd_unique[of 1 a b, simplified] by (auto simp add: coprime_def)
  21.186 -lemma coprime_commute: "coprime a b \<longleftrightarrow> coprime b a" by (simp add: coprime_def gcd_commute)
  21.187 -
  21.188 -lemma coprime_bezout: "coprime a b \<longleftrightarrow> (\<exists>x y. a * x - b * y = 1 \<or> b * x - a * y = 1)"
  21.189 -using coprime_def gcd_bezout by auto
  21.190 -
  21.191 -lemma coprime_divprod: "d dvd a * b  \<Longrightarrow> coprime d a \<Longrightarrow> d dvd b"
  21.192 -  using relprime_dvd_mult_iff[of d a b] by (auto simp add: coprime_def mult.commute)
  21.193 -
  21.194 -lemma coprime_1[simp]: "coprime a 1" by (simp add: coprime_def)
  21.195 -lemma coprime_1'[simp]: "coprime 1 a" by (simp add: coprime_def)
  21.196 -lemma coprime_Suc0[simp]: "coprime a (Suc 0)" by (simp add: coprime_def)
  21.197 -lemma coprime_Suc0'[simp]: "coprime (Suc 0) a" by (simp add: coprime_def)
  21.198 -
  21.199 -lemma gcd_coprime: 
  21.200 -  assumes z: "gcd a b \<noteq> 0" and a: "a = a' * gcd a b" and b: "b = b' * gcd a b" 
  21.201 -  shows    "coprime a' b'"
  21.202 -proof-
  21.203 -  let ?g = "gcd a b"
  21.204 -  {assume bz: "a = 0" from b bz z a have ?thesis by (simp add: gcd_zero coprime_def)}
  21.205 -  moreover 
  21.206 -  {assume az: "a\<noteq> 0" 
  21.207 -    from z have z': "?g > 0" by simp
  21.208 -    from bezout_gcd_strong[OF az, of b] 
  21.209 -    obtain x y where xy: "a*x = b*y + ?g" by blast
  21.210 -    from xy a b have "?g * a'*x = ?g * (b'*y + 1)" by (simp add: algebra_simps)
  21.211 -    hence "?g * (a'*x) = ?g * (b'*y + 1)" by (simp add: mult.assoc)
  21.212 -    hence "a'*x = (b'*y + 1)"
  21.213 -      by (simp only: nat_mult_eq_cancel1[OF z']) 
  21.214 -    hence "a'*x - b'*y = 1" by simp
  21.215 -    with coprime_bezout[of a' b'] have ?thesis by auto}
  21.216 -  ultimately show ?thesis by blast
  21.217 -qed
  21.218 -lemma coprime_0: "coprime d 0 \<longleftrightarrow> d = 1" by (simp add: coprime_def)
  21.219 -lemma coprime_mul: assumes da: "coprime d a" and db: "coprime d b"
  21.220 -  shows "coprime d (a * b)"
  21.221 -proof-
  21.222 -  from da have th: "gcd a d = 1" by (simp add: coprime_def gcd_commute)
  21.223 -  from gcd_mult_cancel[of a d b, OF th] db[unfolded coprime_def] have "gcd d (a*b) = 1"
  21.224 -    by (simp add: gcd_commute)
  21.225 -  thus ?thesis unfolding coprime_def .
  21.226 -qed
  21.227 -lemma coprime_lmul2: assumes dab: "coprime d (a * b)" shows "coprime d b"
  21.228 -using dab unfolding coprime_bezout
  21.229 -apply clarsimp
  21.230 -apply (case_tac "d * x - a * b * y = Suc 0 ", simp_all)
  21.231 -apply (rule_tac x="x" in exI)
  21.232 -apply (rule_tac x="a*y" in exI)
  21.233 -apply (simp add: ac_simps)
  21.234 -apply (rule_tac x="a*x" in exI)
  21.235 -apply (rule_tac x="y" in exI)
  21.236 -apply (simp add: ac_simps)
  21.237 -done
  21.238 -
  21.239 -lemma coprime_rmul2: "coprime d (a * b) \<Longrightarrow> coprime d a"
  21.240 -unfolding coprime_bezout
  21.241 -apply clarsimp
  21.242 -apply (case_tac "d * x - a * b * y = Suc 0 ", simp_all)
  21.243 -apply (rule_tac x="x" in exI)
  21.244 -apply (rule_tac x="b*y" in exI)
  21.245 -apply (simp add: ac_simps)
  21.246 -apply (rule_tac x="b*x" in exI)
  21.247 -apply (rule_tac x="y" in exI)
  21.248 -apply (simp add: ac_simps)
  21.249 -done
  21.250 -lemma coprime_mul_eq: "coprime d (a * b) \<longleftrightarrow> coprime d a \<and>  coprime d b"
  21.251 -  using coprime_rmul2[of d a b] coprime_lmul2[of d a b] coprime_mul[of d a b] 
  21.252 -  by blast
  21.253 -
  21.254 -lemma gcd_coprime_exists:
  21.255 -  assumes nz: "gcd a b \<noteq> 0" 
  21.256 -  shows "\<exists>a' b'. a = a' * gcd a b \<and> b = b' * gcd a b \<and> coprime a' b'"
  21.257 -proof-
  21.258 -  let ?g = "gcd a b"
  21.259 -  from gcd_dvd1[of a b] gcd_dvd2[of a b] 
  21.260 -  obtain a' b' where "a = ?g*a'"  "b = ?g*b'" unfolding dvd_def by blast
  21.261 -  hence ab': "a = a'*?g" "b = b'*?g" by algebra+
  21.262 -  from ab' gcd_coprime[OF nz ab'] show ?thesis by blast
  21.263 -qed
  21.264 -
  21.265 -lemma coprime_exp: "coprime d a ==> coprime d (a^n)" 
  21.266 -  by(induct n, simp_all add: coprime_mul)
  21.267 -
  21.268 -lemma coprime_exp_imp: "coprime a b ==> coprime (a ^n) (b ^n)"
  21.269 -  by (induct n, simp_all add: coprime_mul_eq coprime_commute coprime_exp)
  21.270 -lemma coprime_refl[simp]: "coprime n n \<longleftrightarrow> n = 1" by (simp add: coprime_def)
  21.271 -lemma coprime_plus1[simp]: "coprime (n + 1) n"
  21.272 -  apply (simp add: coprime_bezout)
  21.273 -  apply (rule exI[where x=1])
  21.274 -  apply (rule exI[where x=1])
  21.275 -  apply simp
  21.276 -  done
  21.277 -lemma coprime_minus1: "n \<noteq> 0 ==> coprime (n - 1) n"
  21.278 -  using coprime_plus1[of "n - 1"] coprime_commute[of "n - 1" n] by auto
  21.279 -
  21.280 -lemma bezout_gcd_pow: "\<exists>x y. a ^n * x - b ^ n * y = gcd a b ^ n \<or> b ^ n * x - a ^ n * y = gcd a b ^ n"
  21.281 -proof-
  21.282 -  let ?g = "gcd a b"
  21.283 -  {assume z: "?g = 0" hence ?thesis 
  21.284 -      apply (cases n, simp)
  21.285 -      apply arith
  21.286 -      apply (simp only: z power_0_Suc)
  21.287 -      apply (rule exI[where x=0])
  21.288 -      apply (rule exI[where x=0])
  21.289 -      apply simp
  21.290 -      done }
  21.291 -  moreover
  21.292 -  {assume z: "?g \<noteq> 0"
  21.293 -    from gcd_dvd1[of a b] gcd_dvd2[of a b] obtain a' b' where
  21.294 -      ab': "a = a'*?g" "b = b'*?g" unfolding dvd_def by (auto simp add: ac_simps)
  21.295 -    hence ab'': "?g*a' = a" "?g * b' = b" by algebra+
  21.296 -    from coprime_exp_imp[OF gcd_coprime[OF z ab'], unfolded coprime_bezout, of n]
  21.297 -    obtain x y where "a'^n * x - b'^n * y = 1 \<or> b'^n * x - a'^n * y = 1"  by blast
  21.298 -    hence "?g^n * (a'^n * x - b'^n * y) = ?g^n \<or> ?g^n*(b'^n * x - a'^n * y) = ?g^n"
  21.299 -      using z by auto 
  21.300 -    then have "a^n * x - b^n * y = ?g^n \<or> b^n * x - a^n * y = ?g^n"
  21.301 -      using z ab'' by (simp only: power_mult_distrib[symmetric] 
  21.302 -        diff_mult_distrib2 mult.assoc[symmetric])
  21.303 -    hence  ?thesis by blast }
  21.304 -  ultimately show ?thesis by blast
  21.305 -qed
  21.306 -
  21.307 -lemma gcd_exp: "gcd (a^n) (b^n) = gcd a b^n"
  21.308 -proof-
  21.309 -  let ?g = "gcd (a^n) (b^n)"
  21.310 -  let ?gn = "gcd a b^n"
  21.311 -  {fix e assume H: "e dvd a^n" "e dvd b^n"
  21.312 -    from bezout_gcd_pow[of a n b] obtain x y 
  21.313 -      where xy: "a ^ n * x - b ^ n * y = ?gn \<or> b ^ n * x - a ^ n * y = ?gn" by blast
  21.314 -    from dvd_diff_nat [OF dvd_mult2[OF H(1), of x] dvd_mult2[OF H(2), of y]]
  21.315 -      dvd_diff_nat [OF dvd_mult2[OF H(2), of x] dvd_mult2[OF H(1), of y]] xy
  21.316 -    have "e dvd ?gn" by (cases "a ^ n * x - b ^ n * y = gcd a b ^ n", simp_all)}
  21.317 -  hence th:  "\<forall>e. e dvd a^n \<and> e dvd b^n \<longrightarrow> e dvd ?gn" by blast
  21.318 -  from divides_exp[OF gcd_dvd1[of a b], of n] divides_exp[OF gcd_dvd2[of a b], of n] th
  21.319 -    gcd_unique have "?gn = ?g" by blast thus ?thesis by simp 
  21.320 -qed
  21.321 -
  21.322 -lemma coprime_exp2:  "coprime (a ^ Suc n) (b^ Suc n) \<longleftrightarrow> coprime a b"
  21.323 -by (simp only: coprime_def gcd_exp exp_eq_1) simp
  21.324 -
  21.325 -lemma division_decomp: assumes dc: "(a::nat) dvd b * c"
  21.326 -  shows "\<exists>b' c'. a = b' * c' \<and> b' dvd b \<and> c' dvd c"
  21.327 -proof-
  21.328 -  let ?g = "gcd a b"
  21.329 -  {assume "?g = 0" with dc have ?thesis apply (simp add: gcd_zero)
  21.330 -      apply (rule exI[where x="0"])
  21.331 -      by (rule exI[where x="c"], simp)}
  21.332 -  moreover
  21.333 -  {assume z: "?g \<noteq> 0"
  21.334 -    from gcd_coprime_exists[OF z]
  21.335 -    obtain a' b' where ab': "a = a' * ?g" "b = b' * ?g" "coprime a' b'" by blast
  21.336 -    from gcd_dvd2[of a b] have thb: "?g dvd b" .
  21.337 -    from ab'(1) have "a' dvd a"  unfolding dvd_def by blast  
  21.338 -    with dc have th0: "a' dvd b*c" using dvd_trans[of a' a "b*c"] by simp
  21.339 -    from dc ab'(1,2) have "a'*?g dvd (b'*?g) *c" by auto
  21.340 -    hence "?g*a' dvd ?g * (b' * c)" by (simp add: mult.assoc)
  21.341 -    with z have th_1: "a' dvd b'*c" by simp
  21.342 -    from coprime_divprod[OF th_1 ab'(3)] have thc: "a' dvd c" . 
  21.343 -    from ab' have "a = ?g*a'" by algebra
  21.344 -    with thb thc have ?thesis by blast }
  21.345 -  ultimately show ?thesis by blast
  21.346 -qed
  21.347 -
  21.348 -lemma nat_power_eq_0_iff: "(m::nat) ^ n = 0 \<longleftrightarrow> n \<noteq> 0 \<and> m = 0" by (induct n, auto)
  21.349 -
  21.350 -lemma divides_rev: assumes ab: "(a::nat) ^ n dvd b ^n" and n:"n \<noteq> 0" shows "a dvd b"
  21.351 -proof-
  21.352 -  let ?g = "gcd a b"
  21.353 -  from n obtain m where m: "n = Suc m" by (cases n, simp_all)
  21.354 -  {assume "?g = 0" with ab n have ?thesis by (simp add: gcd_zero)}
  21.355 -  moreover
  21.356 -  {assume z: "?g \<noteq> 0"
  21.357 -    hence zn: "?g ^ n \<noteq> 0" using n by simp
  21.358 -    from gcd_coprime_exists[OF z] 
  21.359 -    obtain a' b' where ab': "a = a' * ?g" "b = b' * ?g" "coprime a' b'" by blast
  21.360 -    from ab have "(a' * ?g) ^ n dvd (b' * ?g)^n" by (simp add: ab'(1,2)[symmetric])
  21.361 -    hence "?g^n*a'^n dvd ?g^n *b'^n" by (simp only: power_mult_distrib mult.commute)
  21.362 -    with zn z n have th0:"a'^n dvd b'^n" by (auto simp add: nat_power_eq_0_iff)
  21.363 -    have "a' dvd a'^n" by (simp add: m)
  21.364 -    with th0 have "a' dvd b'^n" using dvd_trans[of a' "a'^n" "b'^n"] by simp
  21.365 -    hence th1: "a' dvd b'^m * b'" by (simp add: m mult.commute)
  21.366 -    from coprime_divprod[OF th1 coprime_exp[OF ab'(3), of m]]
  21.367 -    have "a' dvd b'" .
  21.368 -    hence "a'*?g dvd b'*?g" by simp
  21.369 -    with ab'(1,2)  have ?thesis by simp }
  21.370 -  ultimately show ?thesis by blast
  21.371 -qed
  21.372 -
  21.373 -lemma divides_mul: assumes mr: "m dvd r" and nr: "n dvd r" and mn:"coprime m n" 
  21.374 -  shows "m * n dvd r"
  21.375 -proof-
  21.376 -  from mr nr obtain m' n' where m': "r = m*m'" and n': "r = n*n'"
  21.377 -    unfolding dvd_def by blast
  21.378 -  from mr n' have "m dvd n'*n" by (simp add: mult.commute)
  21.379 -  hence "m dvd n'" using relprime_dvd_mult_iff[OF mn[unfolded coprime_def]] by simp
  21.380 -  then obtain k where k: "n' = m*k" unfolding dvd_def by blast
  21.381 -  from n' k show ?thesis unfolding dvd_def by auto
  21.382 -qed
  21.383 -
  21.384 -
  21.385 -text \<open>A binary form of the Chinese Remainder Theorem.\<close>
  21.386 -
  21.387 -lemma chinese_remainder: assumes ab: "coprime a b" and a:"a \<noteq> 0" and b:"b \<noteq> 0"
  21.388 -  shows "\<exists>x q1 q2. x = u + q1 * a \<and> x = v + q2 * b"
  21.389 -proof-
  21.390 -  from bezout_add_strong[OF a, of b] bezout_add_strong[OF b, of a]
  21.391 -  obtain d1 x1 y1 d2 x2 y2 where dxy1: "d1 dvd a" "d1 dvd b" "a * x1 = b * y1 + d1" 
  21.392 -    and dxy2: "d2 dvd b" "d2 dvd a" "b * x2 = a * y2 + d2" by blast
  21.393 -  from gcd_unique[of 1 a b, simplified ab[unfolded coprime_def], simplified] 
  21.394 -    dxy1(1,2) dxy2(1,2) have d12: "d1 = 1" "d2 =1" by auto
  21.395 -  let ?x = "v * a * x1 + u * b * x2"
  21.396 -  let ?q1 = "v * x1 + u * y2"
  21.397 -  let ?q2 = "v * y1 + u * x2"
  21.398 -  from dxy2(3)[simplified d12] dxy1(3)[simplified d12] 
  21.399 -  have "?x = u + ?q1 * a" "?x = v + ?q2 * b" by algebra+ 
  21.400 -  thus ?thesis by blast
  21.401 -qed
  21.402 -
  21.403 -text \<open>Primality\<close>
  21.404 -
  21.405 -text \<open>A few useful theorems about primes\<close>
  21.406 -
  21.407 -lemma prime_0[simp]: "~prime 0" by (simp add: prime_def)
  21.408 -lemma prime_1[simp]: "~ prime 1"  by (simp add: prime_def)
  21.409 -lemma prime_Suc0[simp]: "~ prime (Suc 0)"  by (simp add: prime_def)
  21.410 -
  21.411 -lemma prime_ge_2: "prime p ==> p \<ge> 2" by (simp add: prime_def)
  21.412 -
  21.413 -lemma prime_factor: "n \<noteq> 1 \<Longrightarrow> \<exists>p. prime p \<and> p dvd n"
  21.414 -proof (induct n rule: nat_less_induct)
  21.415 -  fix n
  21.416 -  assume H: "\<forall>m<n. m \<noteq> 1 \<longrightarrow> (\<exists>p. prime p \<and> p dvd m)" "n \<noteq> 1"
  21.417 -  show "\<exists>p. prime p \<and> p dvd n"
  21.418 -  proof (cases "n = 0")
  21.419 -    case True
  21.420 -    with two_is_prime show ?thesis by auto
  21.421 -  next
  21.422 -    case nz: False
  21.423 -    show ?thesis
  21.424 -    proof (cases "prime n")
  21.425 -      case True
  21.426 -      then have "prime n \<and> n dvd n" by simp
  21.427 -      then show ?thesis ..
  21.428 -    next
  21.429 -      case n: False
  21.430 -      with nz H(2) obtain k where k: "k dvd n" "k \<noteq> 1" "k \<noteq> n"
  21.431 -        by (auto simp: prime_def) 
  21.432 -      from dvd_imp_le[OF k(1)] nz k(3) have kn: "k < n" by simp
  21.433 -      from H(1)[rule_format, OF kn k(2)] obtain p where p: "prime p" "p dvd k" by blast
  21.434 -      from dvd_trans[OF p(2) k(1)] p(1) show ?thesis by blast
  21.435 -    qed
  21.436 -  qed
  21.437 -qed
  21.438 -
  21.439 -lemma prime_factor_lt:
  21.440 -  assumes p: "prime p" and n: "n \<noteq> 0" and npm:"n = p * m"
  21.441 -  shows "m < n"
  21.442 -proof (cases "m = 0")
  21.443 -  case True
  21.444 -  with n show ?thesis by simp
  21.445 -next
  21.446 -  case m: False
  21.447 -  from npm have mn: "m dvd n" unfolding dvd_def by auto
  21.448 -  from npm m have "n \<noteq> m" using p by auto
  21.449 -  with dvd_imp_le[OF mn] n show ?thesis by simp
  21.450 -qed
  21.451 -
  21.452 -lemma euclid_bound: "\<exists>p. prime p \<and> n < p \<and>  p <= Suc (fact n)"
  21.453 -proof-
  21.454 -  have f1: "fact n + 1 \<noteq> 1" using fact_le[of n] by arith 
  21.455 -  from prime_factor[OF f1] obtain p where p: "prime p" "p dvd fact n + 1" by blast
  21.456 -  from dvd_imp_le[OF p(2)] have pfn: "p \<le> fact n + 1" by simp
  21.457 -  {assume np: "p \<le> n"
  21.458 -    from p(1) have p1: "p \<ge> 1" by (cases p, simp_all)
  21.459 -    from divides_fact[OF p1 np] have pfn': "p dvd fact n" .
  21.460 -    from divides_add_revr[OF pfn' p(2)] p(1) have False by simp}
  21.461 -  hence "n < p" by arith
  21.462 -  with p(1) pfn show ?thesis by auto
  21.463 -qed
  21.464 -
  21.465 -lemma euclid: "\<exists>p. prime p \<and> p > n" using euclid_bound by auto
  21.466 -
  21.467 -lemma primes_infinite: "\<not> (finite {p. prime p})"
  21.468 -apply(simp add: finite_nat_set_iff_bounded_le)
  21.469 -apply (metis euclid linorder_not_le)
  21.470 -done
  21.471 -
  21.472 -lemma coprime_prime: assumes ab: "coprime a b"
  21.473 -  shows "~(prime p \<and> p dvd a \<and> p dvd b)"
  21.474 -proof
  21.475 -  assume "prime p \<and> p dvd a \<and> p dvd b"
  21.476 -  thus False using ab gcd_greatest[of p a b] by (simp add: coprime_def)
  21.477 -qed
  21.478 -lemma coprime_prime_eq: "coprime a b \<longleftrightarrow> (\<forall>p. ~(prime p \<and> p dvd a \<and> p dvd b))" 
  21.479 -  (is "?lhs = ?rhs")
  21.480 -proof-
  21.481 -  {assume "?lhs" with coprime_prime  have ?rhs by blast}
  21.482 -  moreover
  21.483 -  {assume r: "?rhs" and c: "\<not> ?lhs"
  21.484 -    then obtain g where g: "g\<noteq>1" "g dvd a" "g dvd b" unfolding coprime_def by blast
  21.485 -    from prime_factor[OF g(1)] obtain p where p: "prime p" "p dvd g" by blast
  21.486 -    from dvd_trans [OF p(2) g(2)] dvd_trans [OF p(2) g(3)] 
  21.487 -    have "p dvd a" "p dvd b" . with p(1) r have False by blast}
  21.488 -  ultimately show ?thesis by blast
  21.489 -qed
  21.490 -
  21.491 -lemma prime_coprime: assumes p: "prime p" 
  21.492 -  shows "n = 1 \<or> p dvd n \<or> coprime p n"
  21.493 -using p prime_imp_relprime[of p n] by (auto simp add: coprime_def)
  21.494 -
  21.495 -lemma prime_coprime_strong: "prime p \<Longrightarrow> p dvd n \<or> coprime p n"
  21.496 -  using prime_coprime[of p n] by auto
  21.497 -
  21.498 -declare  coprime_0[simp]
  21.499 -
  21.500 -lemma coprime_0'[simp]: "coprime 0 d \<longleftrightarrow> d = 1" by (simp add: coprime_commute[of 0 d])
  21.501 -lemma coprime_bezout_strong: assumes ab: "coprime a b" and b: "b \<noteq> 1"
  21.502 -  shows "\<exists>x y. a * x = b * y + 1"
  21.503 -proof-
  21.504 -  have az: "a \<noteq> 0" by (rule ccontr) (use ab b in auto)
  21.505 -  from bezout_gcd_strong[OF az, of b] ab[unfolded coprime_def]
  21.506 -  show ?thesis by auto
  21.507 -qed
  21.508 -
  21.509 -lemma bezout_prime: assumes p: "prime p"  and pa: "\<not> p dvd a"
  21.510 -  shows "\<exists>x y. a*x = p*y + 1"
  21.511 -proof-
  21.512 -  from p have p1: "p \<noteq> 1" using prime_1 by blast 
  21.513 -  from prime_coprime[OF p, of a] p1 pa have ap: "coprime a p" 
  21.514 -    by (auto simp add: coprime_commute)
  21.515 -  from coprime_bezout_strong[OF ap p1] show ?thesis . 
  21.516 -qed
  21.517 -lemma prime_divprod: assumes p: "prime p" and pab: "p dvd a*b"
  21.518 -  shows "p dvd a \<or> p dvd b"
  21.519 -proof-
  21.520 -  {assume "a=1" hence ?thesis using pab by simp }
  21.521 -  moreover
  21.522 -  {assume "p dvd a" hence ?thesis by blast}
  21.523 -  moreover
  21.524 -  {assume pa: "coprime p a" from coprime_divprod[OF pab pa]  have ?thesis .. }
  21.525 -  ultimately show ?thesis using prime_coprime[OF p, of a] by blast
  21.526 -qed
  21.527 -
  21.528 -lemma prime_divprod_eq: assumes p: "prime p"
  21.529 -  shows "p dvd a*b \<longleftrightarrow> p dvd a \<or> p dvd b"
  21.530 -using p prime_divprod dvd_mult dvd_mult2 by auto
  21.531 -
  21.532 -lemma prime_divexp: assumes p:"prime p" and px: "p dvd x^n"
  21.533 -  shows "p dvd x"
  21.534 -using px
  21.535 -proof(induct n)
  21.536 -  case 0 thus ?case by simp
  21.537 -next
  21.538 -  case (Suc n) 
  21.539 -  hence th: "p dvd x*x^n" by simp
  21.540 -  {assume H: "p dvd x^n"
  21.541 -    from Suc.hyps[OF H] have ?case .}
  21.542 -  with prime_divprod[OF p th] show ?case by blast
  21.543 -qed
  21.544 -
  21.545 -lemma prime_divexp_n: "prime p \<Longrightarrow> p dvd x^n \<Longrightarrow> p^n dvd x^n"
  21.546 -  using prime_divexp[of p x n] divides_exp[of p x n] by blast
  21.547 -
  21.548 -lemma coprime_prime_dvd_ex: assumes xy: "\<not>coprime x y"
  21.549 -  shows "\<exists>p. prime p \<and> p dvd x \<and> p dvd y"
  21.550 -proof-
  21.551 -  from xy[unfolded coprime_def] obtain g where g: "g \<noteq> 1" "g dvd x" "g dvd y" 
  21.552 -    by blast
  21.553 -  from prime_factor[OF g(1)] obtain p where p: "prime p" "p dvd g" by blast
  21.554 -  from g(2,3) dvd_trans[OF p(2)] p(1) show ?thesis by auto
  21.555 -qed
  21.556 -lemma coprime_sos: assumes xy: "coprime x y" 
  21.557 -  shows "coprime (x * y) (x\<^sup>2 + y\<^sup>2)"
  21.558 -proof-
  21.559 -  {assume c: "\<not> coprime (x * y) (x\<^sup>2 + y\<^sup>2)"
  21.560 -    from coprime_prime_dvd_ex[OF c] obtain p 
  21.561 -      where p: "prime p" "p dvd x*y" "p dvd x\<^sup>2 + y\<^sup>2" by blast
  21.562 -    {assume px: "p dvd x"
  21.563 -      from dvd_mult[OF px, of x] p(3) 
  21.564 -        obtain r s where "x * x = p * r" and "x\<^sup>2 + y\<^sup>2 = p * s"
  21.565 -          by (auto elim!: dvdE)
  21.566 -        then have "y\<^sup>2 = p * (s - r)" 
  21.567 -          by (auto simp add: power2_eq_square diff_mult_distrib2)
  21.568 -        then have "p dvd y\<^sup>2" ..
  21.569 -      with prime_divexp[OF p(1), of y 2] have py: "p dvd y" .
  21.570 -      from p(1) px py xy[unfolded coprime, rule_format, of p] prime_1  
  21.571 -      have False by simp }
  21.572 -    moreover
  21.573 -    {assume py: "p dvd y"
  21.574 -      from dvd_mult[OF py, of y] p(3)
  21.575 -        obtain r s where "y * y = p * r" and "x\<^sup>2 + y\<^sup>2 = p * s"
  21.576 -          by (auto elim!: dvdE)
  21.577 -        then have "x\<^sup>2 = p * (s - r)" 
  21.578 -          by (auto simp add: power2_eq_square diff_mult_distrib2)
  21.579 -        then have "p dvd x\<^sup>2" ..
  21.580 -      with prime_divexp[OF p(1), of x 2] have px: "p dvd x" .
  21.581 -      from p(1) px py xy[unfolded coprime, rule_format, of p] prime_1  
  21.582 -      have False by simp }
  21.583 -    ultimately have False using prime_divprod[OF p(1,2)] by blast}
  21.584 -  thus ?thesis by blast
  21.585 -qed
  21.586 -
  21.587 -lemma distinct_prime_coprime: "prime p \<Longrightarrow> prime q \<Longrightarrow> p \<noteq> q \<Longrightarrow> coprime p q"
  21.588 -  unfolding prime_def coprime_prime_eq by blast
  21.589 -
  21.590 -lemma prime_coprime_lt:
  21.591 -  assumes p: "prime p" and x: "0 < x" and xp: "x < p"
  21.592 -  shows "coprime x p"
  21.593 -proof (rule ccontr)
  21.594 -  assume c: "\<not> ?thesis"
  21.595 -  then obtain g where g: "g \<noteq> 1" "g dvd x" "g dvd p" unfolding coprime_def by blast
  21.596 -  from dvd_imp_le[OF g(2)] x xp have gp: "g < p" by arith
  21.597 -  have "g \<noteq> 0" by (rule ccontr) (use g(2) x in simp)
  21.598 -  with g gp p[unfolded prime_def] show False by blast
  21.599 -qed
  21.600 -
  21.601 -lemma prime_odd: "prime p \<Longrightarrow> p = 2 \<or> odd p" unfolding prime_def by auto
  21.602 -
  21.603 -
  21.604 -text \<open>One property of coprimality is easier to prove via prime factors.\<close>
  21.605 -
  21.606 -lemma prime_divprod_pow: 
  21.607 -  assumes p: "prime p" and ab: "coprime a b" and pab: "p^n dvd a * b"
  21.608 -  shows "p^n dvd a \<or> p^n dvd b"
  21.609 -proof-
  21.610 -  {assume "n = 0 \<or> a = 1 \<or> b = 1" with pab have ?thesis 
  21.611 -      apply (cases "n=0", simp_all)
  21.612 -      apply (cases "a=1", simp_all) done}
  21.613 -  moreover
  21.614 -  {assume n: "n \<noteq> 0" and a: "a\<noteq>1" and b: "b\<noteq>1" 
  21.615 -    then obtain m where m: "n = Suc m" by (cases n, auto)
  21.616 -    from divides_exp2[OF n pab] have pab': "p dvd a*b" .
  21.617 -    from prime_divprod[OF p pab'] 
  21.618 -    have "p dvd a \<or> p dvd b" .
  21.619 -    moreover
  21.620 -    {assume pa: "p dvd a"
  21.621 -      have pnba: "p^n dvd b*a" using pab by (simp add: mult.commute)
  21.622 -      from coprime_prime[OF ab, of p] p pa have "\<not> p dvd b" by blast
  21.623 -      with prime_coprime[OF p, of b] b 
  21.624 -      have cpb: "coprime b p" using coprime_commute by blast 
  21.625 -      from coprime_exp[OF cpb] have pnb: "coprime (p^n) b" 
  21.626 -        by (simp add: coprime_commute)
  21.627 -      from coprime_divprod[OF pnba pnb] have ?thesis by blast }
  21.628 -    moreover
  21.629 -    {assume pb: "p dvd b"
  21.630 -      have pnba: "p^n dvd b*a" using pab by (simp add: mult.commute)
  21.631 -      from coprime_prime[OF ab, of p] p pb have "\<not> p dvd a" by blast
  21.632 -      with prime_coprime[OF p, of a] a
  21.633 -      have cpb: "coprime a p" using coprime_commute by blast 
  21.634 -      from coprime_exp[OF cpb] have pnb: "coprime (p^n) a" 
  21.635 -        by (simp add: coprime_commute)
  21.636 -      from coprime_divprod[OF pab pnb] have ?thesis by blast }
  21.637 -    ultimately have ?thesis by blast}
  21.638 -  ultimately show ?thesis by blast
  21.639 -qed
  21.640 -
  21.641 -lemma nat_mult_eq_one: "(n::nat) * m = 1 \<longleftrightarrow> n = 1 \<and> m = 1" (is "?lhs \<longleftrightarrow> ?rhs")
  21.642 -proof
  21.643 -  assume H: "?lhs"
  21.644 -  hence "n dvd 1" "m dvd 1" unfolding dvd_def by (auto simp add: mult.commute)
  21.645 -  thus ?rhs by auto
  21.646 -next
  21.647 -  assume ?rhs then show ?lhs by auto
  21.648 -qed
  21.649 -  
  21.650 -lemma power_Suc0: "Suc 0 ^ n = Suc 0" 
  21.651 -  unfolding One_nat_def[symmetric] power_one ..
  21.652 -
  21.653 -lemma coprime_pow: assumes ab: "coprime a b" and abcn: "a * b = c ^n"
  21.654 -  shows "\<exists>r s. a = r^n  \<and> b = s ^n"
  21.655 -  using ab abcn
  21.656 -proof(induct c arbitrary: a b rule: nat_less_induct)
  21.657 -  fix c a b
  21.658 -  assume H: "\<forall>m<c. \<forall>a b. coprime a b \<longrightarrow> a * b = m ^ n \<longrightarrow> (\<exists>r s. a = r ^ n \<and> b = s ^ n)" "coprime a b" "a * b = c ^ n" 
  21.659 -  let ?ths = "\<exists>r s. a = r^n  \<and> b = s ^n"
  21.660 -  {assume n: "n = 0"
  21.661 -    with H(3) power_one have "a*b = 1" by simp
  21.662 -    hence "a = 1 \<and> b = 1" by simp
  21.663 -    hence ?ths 
  21.664 -      apply -
  21.665 -      apply (rule exI[where x=1])
  21.666 -      apply (rule exI[where x=1])
  21.667 -      using power_one[of  n]
  21.668 -      by simp}
  21.669 -  moreover
  21.670 -  {assume n: "n \<noteq> 0" then obtain m where m: "n = Suc m" by (cases n, auto)
  21.671 -    {assume c: "c = 0"
  21.672 -      with H(3) m H(2) have ?ths apply simp 
  21.673 -        apply (cases "a=0", simp_all) 
  21.674 -        apply (rule exI[where x="0"], simp)
  21.675 -        apply (rule exI[where x="0"], simp)
  21.676 -        done}
  21.677 -    moreover
  21.678 -    {assume "c=1" with H(3) power_one have "a*b = 1" by simp 
  21.679 -        hence "a = 1 \<and> b = 1" by simp
  21.680 -        hence ?ths 
  21.681 -      apply -
  21.682 -      apply (rule exI[where x=1])
  21.683 -      apply (rule exI[where x=1])
  21.684 -      using power_one[of  n]
  21.685 -      by simp}
  21.686 -  moreover
  21.687 -  {assume c: "c\<noteq>1" "c \<noteq> 0"
  21.688 -    from prime_factor[OF c(1)] obtain p where p: "prime p" "p dvd c" by blast
  21.689 -    from prime_divprod_pow[OF p(1) H(2), unfolded H(3), OF divides_exp[OF p(2), of n]] 
  21.690 -    have pnab: "p ^ n dvd a \<or> p^n dvd b" . 
  21.691 -    from p(2) obtain l where l: "c = p*l" unfolding dvd_def by blast
  21.692 -    have pn0: "p^n \<noteq> 0" using n prime_ge_2 [OF p(1)] by simp
  21.693 -    {assume pa: "p^n dvd a"
  21.694 -      then obtain k where k: "a = p^n * k" unfolding dvd_def by blast
  21.695 -      from l have "l dvd c" by auto
  21.696 -      with dvd_imp_le[of l c] c have "l \<le> c" by auto
  21.697 -      moreover {assume "l = c" with l c  have "p = 1" by simp with p have False by simp}
  21.698 -      ultimately have lc: "l < c" by arith
  21.699 -      from coprime_lmul2 [OF H(2)[unfolded k coprime_commute[of "p^n*k" b]]]
  21.700 -      have kb: "coprime k b" by (simp add: coprime_commute) 
  21.701 -      from H(3) l k pn0 have kbln: "k * b = l ^ n" 
  21.702 -        by (auto simp add: power_mult_distrib)
  21.703 -      from H(1)[rule_format, OF lc kb kbln]
  21.704 -      obtain r s where rs: "k = r ^n" "b = s^n" by blast
  21.705 -      from k rs(1) have "a = (p*r)^n" by (simp add: power_mult_distrib)
  21.706 -      with rs(2) have ?ths by blast }
  21.707 -    moreover
  21.708 -    {assume pb: "p^n dvd b"
  21.709 -      then obtain k where k: "b = p^n * k" unfolding dvd_def by blast
  21.710 -      from l have "l dvd c" by auto
  21.711 -      with dvd_imp_le[of l c] c have "l \<le> c" by auto
  21.712 -      moreover {assume "l = c" with l c  have "p = 1" by simp with p have False by simp}
  21.713 -      ultimately have lc: "l < c" by arith
  21.714 -      from coprime_lmul2 [OF H(2)[unfolded k coprime_commute[of "p^n*k" a]]]
  21.715 -      have kb: "coprime k a" by (simp add: coprime_commute) 
  21.716 -      from H(3) l k pn0 n have kbln: "k * a = l ^ n" 
  21.717 -        by (simp add: power_mult_distrib mult.commute)
  21.718 -      from H(1)[rule_format, OF lc kb kbln]
  21.719 -      obtain r s where rs: "k = r ^n" "a = s^n" by blast
  21.720 -      from k rs(1) have "b = (p*r)^n" by (simp add: power_mult_distrib)
  21.721 -      with rs(2) have ?ths by blast }
  21.722 -    ultimately have ?ths using pnab by blast}
  21.723 -  ultimately have ?ths by blast}
  21.724 -ultimately show ?ths by blast
  21.725 -qed
  21.726 -
  21.727 -text \<open>More useful lemmas.\<close>
  21.728 -lemma prime_product: 
  21.729 -  assumes "prime (p * q)"
  21.730 -  shows "p = 1 \<or> q = 1"
  21.731 -proof -
  21.732 -  from assms have 
  21.733 -    "1 < p * q" and P: "\<And>m. m dvd p * q \<Longrightarrow> m = 1 \<or> m = p * q"
  21.734 -    unfolding prime_def by auto
  21.735 -  from \<open>1 < p * q\<close> have "p \<noteq> 0" by (cases p) auto
  21.736 -  then have Q: "p = p * q \<longleftrightarrow> q = 1" by auto
  21.737 -  have "p dvd p * q" by simp
  21.738 -  then have "p = 1 \<or> p = p * q" by (rule P)
  21.739 -  then show ?thesis by (simp add: Q)
  21.740 -qed
  21.741 -
  21.742 -lemma prime_exp: "prime (p^n) \<longleftrightarrow> prime p \<and> n = 1"
  21.743 -proof(induct n)
  21.744 -  case 0 thus ?case by simp
  21.745 -next
  21.746 -  case (Suc n)
  21.747 -  {assume "p = 0" hence ?case by simp}
  21.748 -  moreover
  21.749 -  {assume "p=1" hence ?case by simp}
  21.750 -  moreover
  21.751 -  {assume p: "p \<noteq> 0" "p\<noteq>1"
  21.752 -    {assume pp: "prime (p^Suc n)"
  21.753 -      hence "p = 1 \<or> p^n = 1" using prime_product[of p "p^n"] by simp
  21.754 -      with p have n: "n = 0" 
  21.755 -        by (simp only: exp_eq_1 ) simp
  21.756 -      with pp have "prime p \<and> Suc n = 1" by simp}
  21.757 -    moreover
  21.758 -    {assume n: "prime p \<and> Suc n = 1" hence "prime (p^Suc n)" by simp}
  21.759 -    ultimately have ?case by blast}
  21.760 -  ultimately show ?case by blast
  21.761 -qed
  21.762 -
  21.763 -lemma prime_power_mult: 
  21.764 -  assumes p: "prime p" and xy: "x * y = p ^ k"
  21.765 -  shows "\<exists>i j. x = p ^i \<and> y = p^ j"
  21.766 -  using xy
  21.767 -proof(induct k arbitrary: x y)
  21.768 -  case 0
  21.769 -  thus ?case apply simp by (rule exI[where x="0"], simp)
  21.770 -next
  21.771 -  case (Suc k x y)
  21.772 -  have p0: "p \<noteq> 0" by (rule ccontr) (use p in simp) 
  21.773 -  from Suc.prems have pxy: "p dvd x*y" by auto
  21.774 -  from prime_divprod[OF p pxy] show ?case
  21.775 -  proof
  21.776 -    assume px: "p dvd x"
  21.777 -    then obtain d where d: "x = p*d" unfolding dvd_def by blast
  21.778 -    from Suc.prems d  have "p*d*y = p^Suc k" by simp
  21.779 -    hence th: "d*y = p^k" using p0 by simp
  21.780 -    from Suc.hyps[OF th] obtain i j where ij: "d = p^i" "y = p^j" by blast
  21.781 -    with d have "x = p^Suc i" by simp 
  21.782 -    with ij(2) show ?thesis by blast
  21.783 -  next
  21.784 -    assume px: "p dvd y"
  21.785 -    then obtain d where d: "y = p*d" unfolding dvd_def by blast
  21.786 -    from Suc.prems d  have "p*d*x = p^Suc k" by (simp add: mult.commute)
  21.787 -    hence th: "d*x = p^k" using p0 by simp
  21.788 -    from Suc.hyps[OF th] obtain i j where ij: "d = p^i" "x = p^j" by blast
  21.789 -    with d have "y = p^Suc i" by simp 
  21.790 -    with ij(2) show ?thesis by blast
  21.791 -  qed
  21.792 -qed
  21.793 -
  21.794 -lemma prime_power_exp: assumes p: "prime p" and n:"n \<noteq> 0" 
  21.795 -  and xn: "x^n = p^k" shows "\<exists>i. x = p^i"
  21.796 -  using n xn
  21.797 -proof(induct n arbitrary: k)
  21.798 -  case 0 thus ?case by simp
  21.799 -next
  21.800 -  case (Suc n k) hence th: "x*x^n = p^k" by simp
  21.801 -  {assume "n = 0" with Suc have ?case by simp (rule exI[where x="k"], simp)}
  21.802 -  moreover
  21.803 -  {assume n: "n \<noteq> 0"
  21.804 -    from prime_power_mult[OF p th] 
  21.805 -    obtain i j where ij: "x = p^i" "x^n = p^j"by blast
  21.806 -    from Suc.hyps[OF n ij(2)] have ?case .}
  21.807 -  ultimately show ?case by blast
  21.808 -qed
  21.809 -
  21.810 -lemma divides_primepow: assumes p: "prime p" 
  21.811 -  shows "d dvd p^k \<longleftrightarrow> (\<exists> i. i \<le> k \<and> d = p ^i)"
  21.812 -proof
  21.813 -  assume H: "d dvd p^k" then obtain e where e: "d*e = p^k" 
  21.814 -    unfolding dvd_def  apply (auto simp add: mult.commute) by blast
  21.815 -  from prime_power_mult[OF p e] obtain i j where ij: "d = p^i" "e=p^j" by blast
  21.816 -  from prime_ge_2[OF p] have p1: "p > 1" by arith
  21.817 -  from e ij have "p^(i + j) = p^k" by (simp add: power_add)
  21.818 -  hence "i + j = k" using power_inject_exp[of p "i+j" k, OF p1] by simp 
  21.819 -  hence "i \<le> k" by arith
  21.820 -  with ij(1) show "\<exists>i\<le>k. d = p ^ i" by blast
  21.821 -next
  21.822 -  {fix i assume H: "i \<le> k" "d = p^i"
  21.823 -    hence "\<exists>j. k = i + j" by arith
  21.824 -    then obtain j where j: "k = i + j" by blast
  21.825 -    hence "p^k = p^j*d" using H(2) by (simp add: power_add)
  21.826 -    hence "d dvd p^k" unfolding dvd_def by auto}
  21.827 -  thus "\<exists>i\<le>k. d = p ^ i \<Longrightarrow> d dvd p ^ k" by blast
  21.828 -qed
  21.829 -
  21.830 -lemma coprime_divisors: "d dvd a \<Longrightarrow> e dvd b \<Longrightarrow> coprime a b \<Longrightarrow> coprime d e"
  21.831 -  by (auto simp add: dvd_def coprime)
  21.832 -
  21.833 -lemma mult_inj_if_coprime_nat:
  21.834 -  "inj_on f A \<Longrightarrow> inj_on g B \<Longrightarrow> \<forall>a\<in>A. \<forall>b\<in>B. Primes.coprime (f a) (g b) \<Longrightarrow>
  21.835 -    inj_on (\<lambda>(a, b). f a * g b) (A \<times> B)"
  21.836 -apply (auto simp add: inj_on_def)
  21.837 -apply (metis coprime_def dvd_antisym dvd_triv_left relprime_dvd_mult_iff)
  21.838 -apply (metis coprime_commute coprime_divprod dvd_antisym dvd_triv_right)
  21.839 -done
  21.840 -
  21.841 -declare power_Suc0[simp del]
  21.842 -
  21.843 -end
    22.1 --- a/src/HOL/Old_Number_Theory/Quadratic_Reciprocity.thy	Tue Oct 18 07:04:08 2016 +0200
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,637 +0,0 @@
    22.4 -(*  Title:      HOL/Old_Number_Theory/Quadratic_Reciprocity.thy
    22.5 -    Authors:    Jeremy Avigad, David Gray, and Adam Kramer
    22.6 -*)
    22.7 -
    22.8 -section \<open>The law of Quadratic reciprocity\<close>
    22.9 -
   22.10 -theory Quadratic_Reciprocity
   22.11 -imports Gauss
   22.12 -begin
   22.13 -
   22.14 -text \<open>
   22.15 -  Lemmas leading up to the proof of theorem 3.3 in Niven and
   22.16 -  Zuckerman's presentation.
   22.17 -\<close>
   22.18 -
   22.19 -context GAUSS
   22.20 -begin
   22.21 -
   22.22 -lemma QRLemma1: "a * sum id A =
   22.23 -  p * sum (%x. ((x * a) div p)) A + sum id D + sum id E"
   22.24 -proof -
   22.25 -  from finite_A have "a * sum id A = sum (%x. a * x) A"
   22.26 -    by (auto simp add: sum_const_mult id_def)
   22.27 -  also have "sum (%x. a * x) = sum (%x. x * a)"
   22.28 -    by (auto simp add: mult.commute)
   22.29 -  also have "sum (%x. x * a) A = sum id B"
   22.30 -    by (simp add: B_def sum.reindex [OF inj_on_xa_A])
   22.31 -  also have "... = sum (%x. p * (x div p) + StandardRes p x) B"
   22.32 -    by (auto simp add: StandardRes_def mult_div_mod_eq [symmetric])
   22.33 -  also have "... = sum (%x. p * (x div p)) B + sum (StandardRes p) B"
   22.34 -    by (rule sum.distrib)
   22.35 -  also have "sum (StandardRes p) B = sum id C"
   22.36 -    by (auto simp add: C_def sum.reindex [OF SR_B_inj])
   22.37 -  also from C_eq have "... = sum id (D \<union> E)"
   22.38 -    by auto
   22.39 -  also from finite_D finite_E have "... = sum id D + sum id E"
   22.40 -    by (rule sum.union_disjoint) (auto simp add: D_def E_def)
   22.41 -  also have "sum (%x. p * (x div p)) B =
   22.42 -      sum ((%x. p * (x div p)) o (%x. (x * a))) A"
   22.43 -    by (auto simp add: B_def sum.reindex inj_on_xa_A)
   22.44 -  also have "... = sum (%x. p * ((x * a) div p)) A"
   22.45 -    by (auto simp add: o_def)
   22.46 -  also from finite_A have "sum (%x. p * ((x * a) div p)) A =
   22.47 -    p * sum (%x. ((x * a) div p)) A"
   22.48 -    by (auto simp add: sum_const_mult)
   22.49 -  finally show ?thesis by arith
   22.50 -qed
   22.51 -
   22.52 -lemma QRLemma2: "sum id A = p * int (card E) - sum id E +
   22.53 -  sum id D"
   22.54 -proof -
   22.55 -  from F_Un_D_eq_A have "sum id A = sum id (D \<union> F)"
   22.56 -    by (simp add: Un_commute)
   22.57 -  also from F_D_disj finite_D finite_F
   22.58 -  have "... = sum id D + sum id F"
   22.59 -    by (auto simp add: Int_commute intro: sum.union_disjoint)
   22.60 -  also from F_def have "F = (%x. (p - x)) ` E"
   22.61 -    by auto
   22.62 -  also from finite_E inj_on_pminusx_E have "sum id ((%x. (p - x)) ` E) =
   22.63 -      sum (%x. (p - x)) E"
   22.64 -    by (auto simp add: sum.reindex)
   22.65 -  also from finite_E have "sum (op - p) E = sum (%x. p) E - sum id E"
   22.66 -    by (auto simp add: sum_subtractf id_def)
   22.67 -  also from finite_E have "sum (%x. p) E = p * int(card E)"
   22.68 -    by (intro sum_const)
   22.69 -  finally show ?thesis
   22.70 -    by arith
   22.71 -qed
   22.72 -
   22.73 -lemma QRLemma3: "(a - 1) * sum id A =
   22.74 -    p * (sum (%x. ((x * a) div p)) A - int(card E)) + 2 * sum id E"
   22.75 -proof -
   22.76 -  have "(a - 1) * sum id A = a * sum id A - sum id A"
   22.77 -    by (auto simp add: left_diff_distrib)
   22.78 -  also note QRLemma1
   22.79 -  also from QRLemma2 have "p * (\<Sum>x \<in> A. x * a div p) + sum id D +
   22.80 -     sum id E - sum id A =
   22.81 -      p * (\<Sum>x \<in> A. x * a div p) + sum id D +
   22.82 -      sum id E - (p * int (card E) - sum id E + sum id D)"
   22.83 -    by auto
   22.84 -  also have "... = p * (\<Sum>x \<in> A. x * a div p) -
   22.85 -      p * int (card E) + 2 * sum id E"
   22.86 -    by arith
   22.87 -  finally show ?thesis
   22.88 -    by (auto simp only: right_diff_distrib)
   22.89 -qed
   22.90 -
   22.91 -lemma QRLemma4: "a \<in> zOdd ==>
   22.92 -    (sum (%x. ((x * a) div p)) A \<in> zEven) = (int(card E): zEven)"
   22.93 -proof -
   22.94 -  assume a_odd: "a \<in> zOdd"
   22.95 -  from QRLemma3 have a: "p * (sum (%x. ((x * a) div p)) A - int(card E)) =
   22.96 -      (a - 1) * sum id A - 2 * sum id E"
   22.97 -    by arith
   22.98 -  from a_odd have "a - 1 \<in> zEven"
   22.99 -    by (rule odd_minus_one_even)
  22.100 -  hence "(a - 1) * sum id A \<in> zEven"
  22.101 -    by (rule even_times_either)
  22.102 -  moreover have "2 * sum id E \<in> zEven"
  22.103 -    by (auto simp add: zEven_def)
  22.104 -  ultimately have "(a - 1) * sum id A - 2 * sum id E \<in> zEven"
  22.105 -    by (rule even_minus_even)
  22.106 -  with a have "p * (sum (%x. ((x * a) div p)) A - int(card E)): zEven"
  22.107 -    by simp
  22.108 -  hence "p \<in> zEven | (sum (%x. ((x * a) div p)) A - int(card E)): zEven"
  22.109 -    by (rule EvenOdd.even_product)
  22.110 -  with p_odd have "(sum (%x. ((x * a) div p)) A - int(card E)): zEven"
  22.111 -    by (auto simp add: odd_iff_not_even)
  22.112 -  thus ?thesis
  22.113 -    by (auto simp only: even_diff [symmetric])
  22.114 -qed
  22.115 -
  22.116 -lemma QRLemma5: "a \<in> zOdd ==>
  22.117 -   (-1::int)^(card E) = (-1::int)^(nat(sum (%x. ((x * a) div p)) A))"
  22.118 -proof -
  22.119 -  assume "a \<in> zOdd"
  22.120 -  from QRLemma4 [OF this] have
  22.121 -    "(int(card E): zEven) = (sum (%x. ((x * a) div p)) A \<in> zEven)" ..
  22.122 -  moreover have "0 \<le> int(card E)"
  22.123 -    by auto
  22.124 -  moreover have "0 \<le> sum (%x. ((x * a) div p)) A"
  22.125 -    proof (intro sum_nonneg)
  22.126 -      show "\<forall>x \<in> A. 0 \<le> x * a div p"
  22.127 -      proof
  22.128 -        fix x
  22.129 -        assume "x \<in> A"
  22.130 -        then have "0 \<le> x"
  22.131 -          by (auto simp add: A_def)
  22.132 -        with a_nonzero have "0 \<le> x * a"
  22.133 -          by (auto simp add: zero_le_mult_iff)
  22.134 -        with p_g_2 show "0 \<le> x * a div p"
  22.135 -          by (auto simp add: pos_imp_zdiv_nonneg_iff)
  22.136 -      qed
  22.137 -    qed
  22.138 -  ultimately have "(-1::int)^nat((int (card E))) =
  22.139 -      (-1)^nat(((\<Sum>x \<in> A. x * a div p)))"
  22.140 -    by (intro neg_one_power_parity, auto)
  22.141 -  also have "nat (int(card E)) = card E"
  22.142 -    by auto
  22.143 -  finally show ?thesis .
  22.144 -qed
  22.145 -
  22.146 -end
  22.147 -
  22.148 -lemma MainQRLemma: "[| a \<in> zOdd; 0 < a; ~([a = 0] (mod p)); zprime p; 2 < p;
  22.149 -  A = {x. 0 < x & x \<le> (p - 1) div 2} |] ==>
  22.150 -  (Legendre a p) = (-1::int)^(nat(sum (%x. ((x * a) div p)) A))"
  22.151 -  apply (subst GAUSS.gauss_lemma)
  22.152 -  apply (auto simp add: GAUSS_def)
  22.153 -  apply (subst GAUSS.QRLemma5)
  22.154 -  apply (auto simp add: GAUSS_def)
  22.155 -  apply (simp add: GAUSS.A_def [OF GAUSS.intro] GAUSS_def)
  22.156 -  done
  22.157 -
  22.158 -
  22.159 -subsection \<open>Stuff about S, S1 and S2\<close>
  22.160 -
  22.161 -locale QRTEMP =
  22.162 -  fixes p     :: "int"
  22.163 -  fixes q     :: "int"
  22.164 -
  22.165 -  assumes p_prime: "zprime p"
  22.166 -  assumes p_g_2: "2 < p"
  22.167 -  assumes q_prime: "zprime q"
  22.168 -  assumes q_g_2: "2 < q"
  22.169 -  assumes p_neq_q:      "p \<noteq> q"
  22.170 -begin
  22.171 -
  22.172 -definition P_set :: "int set"
  22.173 -  where "P_set = {x. 0 < x & x \<le> ((p - 1) div 2) }"
  22.174 -
  22.175 -definition Q_set :: "int set"
  22.176 -  where "Q_set = {x. 0 < x & x \<le> ((q - 1) div 2) }"
  22.177 -  
  22.178 -definition S :: "(int * int) set"
  22.179 -  where "S = P_set \<times> Q_set"
  22.180 -
  22.181 -definition S1 :: "(int * int) set"
  22.182 -  where "S1 = { (x, y). (x, y):S & ((p * y) < (q * x)) }"
  22.183 -
  22.184 -definition S2 :: "(int * int) set"
  22.185 -  where "S2 = { (x, y). (x, y):S & ((q * x) < (p * y)) }"
  22.186 -
  22.187 -definition f1 :: "int => (int * int) set"
  22.188 -  where "f1 j = { (j1, y). (j1, y):S & j1 = j & (y \<le> (q * j) div p) }"
  22.189 -
  22.190 -definition f2 :: "int => (int * int) set"
  22.191 -  where "f2 j = { (x, j1). (x, j1):S & j1 = j & (x \<le> (p * j) div q) }"
  22.192 -
  22.193 -lemma p_fact: "0 < (p - 1) div 2"
  22.194 -proof -
  22.195 -  from p_g_2 have "2 \<le> p - 1" by arith
  22.196 -  then have "2 div 2 \<le> (p - 1) div 2" by (rule zdiv_mono1, auto)
  22.197 -  then show ?thesis by auto
  22.198 -qed
  22.199 -
  22.200 -lemma q_fact: "0 < (q - 1) div 2"
  22.201 -proof -
  22.202 -  from q_g_2 have "2 \<le> q - 1" by arith
  22.203 -  then have "2 div 2 \<le> (q - 1) div 2" by (rule zdiv_mono1, auto)
  22.204 -  then show ?thesis by auto
  22.205 -qed
  22.206 -
  22.207 -lemma pb_neq_qa:
  22.208 -  assumes "1 \<le> b" and "b \<le> (q - 1) div 2"
  22.209 -  shows "p * b \<noteq> q * a"
  22.210 -proof
  22.211 -  assume "p * b = q * a"
  22.212 -  then have "q dvd (p * b)" by (auto simp add: dvd_def)
  22.213 -  with q_prime p_g_2 have "q dvd p | q dvd b"
  22.214 -    by (auto simp add: zprime_zdvd_zmult)
  22.215 -  moreover have "~ (q dvd p)"
  22.216 -  proof
  22.217 -    assume "q dvd p"
  22.218 -    with p_prime have "q = 1 | q = p"
  22.219 -      apply (auto simp add: zprime_def QRTEMP_def)
  22.220 -      apply (drule_tac x = q and R = False in allE)
  22.221 -      apply (simp add: QRTEMP_def)
  22.222 -      apply (subgoal_tac "0 \<le> q", simp add: QRTEMP_def)
  22.223 -      apply (insert assms)
  22.224 -      apply (auto simp add: QRTEMP_def)
  22.225 -      done
  22.226 -    with q_g_2 p_neq_q show False by auto
  22.227 -  qed
  22.228 -  ultimately have "q dvd b" by auto
  22.229 -  then have "q \<le> b"
  22.230 -  proof -
  22.231 -    assume "q dvd b"
  22.232 -    moreover from assms have "0 < b" by auto
  22.233 -    ultimately show ?thesis using zdvd_bounds [of q b] by auto
  22.234 -  qed
  22.235 -  with assms have "q \<le> (q - 1) div 2" by auto
  22.236 -  then have "2 * q \<le> 2 * ((q - 1) div 2)" by arith
  22.237 -  then have "2 * q \<le> q - 1"
  22.238 -  proof -
  22.239 -    assume a: "2 * q \<le> 2 * ((q - 1) div 2)"
  22.240 -    with assms have "q \<in> zOdd" by (auto simp add: QRTEMP_def zprime_zOdd_eq_grt_2)
  22.241 -    with odd_minus_one_even have "(q - 1):zEven" by auto
  22.242 -    with even_div_2_prop2 have "(q - 1) = 2 * ((q - 1) div 2)" by auto
  22.243 -    with a show ?thesis by auto
  22.244 -  qed
  22.245 -  then have p1: "q \<le> -1" by arith
  22.246 -  with q_g_2 show False by auto
  22.247 -qed
  22.248 -
  22.249 -lemma P_set_finite: "finite (P_set)"
  22.250 -  using p_fact by (auto simp add: P_set_def bdd_int_set_l_le_finite)
  22.251 -
  22.252 -lemma Q_set_finite: "finite (Q_set)"
  22.253 -  using q_fact by (auto simp add: Q_set_def bdd_int_set_l_le_finite)
  22.254 -
  22.255 -lemma S_finite: "finite S"
  22.256 -  by (auto simp add: S_def  P_set_finite Q_set_finite finite_cartesian_product)
  22.257 -
  22.258 -lemma S1_finite: "finite S1"
  22.259 -proof -
  22.260 -  have "finite S" by (auto simp add: S_finite)
  22.261 -  moreover have "S1 \<subseteq> S" by (auto simp add: S1_def S_def)
  22.262 -  ultimately show ?thesis by (auto simp add: finite_subset)
  22.263 -qed
  22.264 -
  22.265 -lemma S2_finite: "finite S2"
  22.266 -proof -
  22.267 -  have "finite S" by (auto simp add: S_finite)
  22.268 -  moreover have "S2 \<subseteq> S" by (auto simp add: S2_def S_def)
  22.269 -  ultimately show ?thesis by (auto simp add: finite_subset)
  22.270 -qed
  22.271 -
  22.272 -lemma P_set_card: "(p - 1) div 2 = int (card (P_set))"
  22.273 -  using p_fact by (auto simp add: P_set_def card_bdd_int_set_l_le)
  22.274 -
  22.275 -lemma Q_set_card: "(q - 1) div 2 = int (card (Q_set))"
  22.276 -  using q_fact by (auto simp add: Q_set_def card_bdd_int_set_l_le)
  22.277 -
  22.278 -lemma S_card: "((p - 1) div 2) * ((q - 1) div 2) = int (card(S))"
  22.279 -  using P_set_card Q_set_card P_set_finite Q_set_finite
  22.280 -  by (simp add: S_def)
  22.281 -
  22.282 -lemma S1_Int_S2_prop: "S1 \<inter> S2 = {}"
  22.283 -  by (auto simp add: S1_def S2_def)
  22.284 -
  22.285 -lemma S1_Union_S2_prop: "S = S1 \<union> S2"
  22.286 -  apply (auto simp add: S_def P_set_def Q_set_def S1_def S2_def)
  22.287 -proof -
  22.288 -  fix a and b
  22.289 -  assume "~ q * a < p * b" and b1: "0 < b" and b2: "b \<le> (q - 1) div 2"
  22.290 -  with less_linear have "(p * b < q * a) | (p * b = q * a)" by auto
  22.291 -  moreover from pb_neq_qa b1 b2 have "(p * b \<noteq> q * a)" by auto
  22.292 -  ultimately show "p * b < q * a" by auto
  22.293 -qed
  22.294 -
  22.295 -lemma card_sum_S1_S2: "((p - 1) div 2) * ((q - 1) div 2) =
  22.296 -    int(card(S1)) + int(card(S2))"
  22.297 -proof -
  22.298 -  have "((p - 1) div 2) * ((q - 1) div 2) = int (card(S))"
  22.299 -    by (auto simp add: S_card)
  22.300 -  also have "... = int( card(S1) + card(S2))"
  22.301 -    apply (insert S1_finite S2_finite S1_Int_S2_prop S1_Union_S2_prop)
  22.302 -    apply (drule card_Un_disjoint, auto)
  22.303 -    done
  22.304 -  also have "... = int(card(S1)) + int(card(S2))" by auto
  22.305 -  finally show ?thesis .
  22.306 -qed
  22.307 -
  22.308 -lemma aux1a:
  22.309 -  assumes "0 < a" and "a \<le> (p - 1) div 2"
  22.310 -    and "0 < b" and "b \<le> (q - 1) div 2"
  22.311 -  shows "(p * b < q * a) = (b \<le> q * a div p)"
  22.312 -proof -
  22.313 -  have "p * b < q * a ==> b \<le> q * a div p"
  22.314 -  proof -
  22.315 -    assume "p * b < q * a"
  22.316 -    then have "p * b \<le> q * a" by auto
  22.317 -    then have "(p * b) div p \<le> (q * a) div p"
  22.318 -      by (rule zdiv_mono1) (insert p_g_2, auto)
  22.319 -    then show "b \<le> (q * a) div p"
  22.320 -      apply (subgoal_tac "p \<noteq> 0")
  22.321 -      apply (frule nonzero_mult_div_cancel_left, force)
  22.322 -      apply (insert p_g_2, auto)
  22.323 -      done
  22.324 -  qed
  22.325 -  moreover have "b \<le> q * a div p ==> p * b < q * a"
  22.326 -  proof -
  22.327 -    assume "b \<le> q * a div p"
  22.328 -    then have "p * b \<le> p * ((q * a) div p)"
  22.329 -      using p_g_2 by (auto simp add: mult_le_cancel_left)
  22.330 -    also have "... \<le> q * a"
  22.331 -      by (rule zdiv_leq_prop) (insert p_g_2, auto)
  22.332 -    finally have "p * b \<le> q * a" .
  22.333 -    then have "p * b < q * a | p * b = q * a"
  22.334 -      by (simp only: order_le_imp_less_or_eq)
  22.335 -    moreover have "p * b \<noteq> q * a"
  22.336 -      by (rule pb_neq_qa) (insert assms, auto)
  22.337 -    ultimately show ?thesis by auto
  22.338 -  qed
  22.339 -  ultimately show ?thesis ..
  22.340 -qed
  22.341 -
  22.342 -lemma aux1b:
  22.343 -  assumes "0 < a" and "a \<le> (p - 1) div 2"
  22.344 -    and "0 < b" and "b \<le> (q - 1) div 2"
  22.345 -  shows "(q * a < p * b) = (a \<le> p * b div q)"
  22.346 -proof -
  22.347 -  have "q * a < p * b ==> a \<le> p * b div q"
  22.348 -  proof -
  22.349 -    assume "q * a < p * b"
  22.350 -    then have "q * a \<le> p * b" by auto
  22.351 -    then have "(q * a) div q \<le> (p * b) div q"
  22.352 -      by (rule zdiv_mono1) (insert q_g_2, auto)
  22.353 -    then show "a \<le> (p * b) div q"
  22.354 -      apply (subgoal_tac "q \<noteq> 0")
  22.355 -      apply (frule nonzero_mult_div_cancel_left, force)
  22.356 -      apply (insert q_g_2, auto)
  22.357 -      done
  22.358 -  qed
  22.359 -  moreover have "a \<le> p * b div q ==> q * a < p * b"
  22.360 -  proof -
  22.361 -    assume "a \<le> p * b div q"
  22.362 -    then have "q * a \<le> q * ((p * b) div q)"
  22.363 -      using q_g_2 by (auto simp add: mult_le_cancel_left)
  22.364 -    also have "... \<le> p * b"
  22.365 -      by (rule zdiv_leq_prop) (insert q_g_2, auto)
  22.366 -    finally have "q * a \<le> p * b" .
  22.367 -    then have "q * a < p * b | q * a = p * b"
  22.368 -      by (simp only: order_le_imp_less_or_eq)
  22.369 -    moreover have "p * b \<noteq> q * a"
  22.370 -      by (rule  pb_neq_qa) (insert assms, auto)
  22.371 -    ultimately show ?thesis by auto
  22.372 -  qed
  22.373 -  ultimately show ?thesis ..
  22.374 -qed
  22.375 -
  22.376 -lemma (in -) aux2:
  22.377 -  assumes "zprime p" and "zprime q" and "2 < p" and "2 < q"
  22.378 -  shows "(q * ((p - 1) div 2)) div p \<le> (q - 1) div 2"
  22.379 -proof-
  22.380 -  (* Set up what's even and odd *)
  22.381 -  from assms have "p \<in> zOdd & q \<in> zOdd"
  22.382 -    by (auto simp add:  zprime_zOdd_eq_grt_2)
  22.383 -  then have even1: "(p - 1):zEven & (q - 1):zEven"
  22.384 -    by (auto simp add: odd_minus_one_even)
  22.385 -  then have even2: "(2 * p):zEven & ((q - 1) * p):zEven"
  22.386 -    by (auto simp add: zEven_def)
  22.387 -  then have even3: "(((q - 1) * p) + (2 * p)):zEven"
  22.388 -    by (auto simp: EvenOdd.even_plus_even)
  22.389 -  (* using these prove it *)
  22.390 -  from assms have "q * (p - 1) < ((q - 1) * p) + (2 * p)"
  22.391 -    by (auto simp add: int_distrib)
  22.392 -  then have "((p - 1) * q) div 2 < (((q - 1) * p) + (2 * p)) div 2"
  22.393 -    apply (rule_tac x = "((p - 1) * q)" in even_div_2_l)
  22.394 -    by (auto simp add: even3, auto simp add: ac_simps)
  22.395 -  also have "((p - 1) * q) div 2 = q * ((p - 1) div 2)"
  22.396 -    by (auto simp add: even1 even_prod_div_2)
  22.397 -  also have "(((q - 1) * p) + (2 * p)) div 2 = (((q - 1) div 2) * p) + p"
  22.398 -    by (auto simp add: even1 even2 even_prod_div_2 even_sum_div_2)
  22.399 -  finally show ?thesis
  22.400 -    apply (rule_tac x = " q * ((p - 1) div 2)" and
  22.401 -                    y = "(q - 1) div 2" in div_prop2)
  22.402 -    using assms by auto
  22.403 -qed
  22.404 -
  22.405 -lemma aux3a: "\<forall>j \<in> P_set. int (card (f1 j)) = (q * j) div p"
  22.406 -proof
  22.407 -  fix j
  22.408 -  assume j_fact: "j \<in> P_set"
  22.409 -  have "int (card (f1 j)) = int (card {y. y \<in> Q_set & y \<le> (q * j) div p})"
  22.410 -  proof -
  22.411 -    have "finite (f1 j)"
  22.412 -    proof -
  22.413 -      have "(f1 j) \<subseteq> S" by (auto simp add: f1_def)
  22.414 -      with S_finite show ?thesis by (auto simp add: finite_subset)
  22.415 -    qed
  22.416 -    moreover have "inj_on (%(x,y). y) (f1 j)"
  22.417 -      by (auto simp add: f1_def inj_on_def)
  22.418 -    ultimately have "card ((%(x,y). y) ` (f1 j)) = card  (f1 j)"
  22.419 -      by (auto simp add: f1_def card_image)
  22.420 -    moreover have "((%(x,y). y) ` (f1 j)) = {y. y \<in> Q_set & y \<le> (q * j) div p}"
  22.421 -      using j_fact by (auto simp add: f1_def S_def Q_set_def P_set_def image_def)
  22.422 -    ultimately show ?thesis by (auto simp add: f1_def)
  22.423 -  qed
  22.424 -  also have "... = int (card {y. 0 < y & y \<le> (q * j) div p})"
  22.425 -  proof -
  22.426 -    have "{y. y \<in> Q_set & y \<le> (q * j) div p} =
  22.427 -        {y. 0 < y & y \<le> (q * j) div p}"
  22.428 -      apply (auto simp add: Q_set_def)
  22.429 -    proof -
  22.430 -      fix x
  22.431 -      assume x: "0 < x" "x \<le> q * j div p"
  22.432 -      with j_fact P_set_def  have "j \<le> (p - 1) div 2" by auto
  22.433 -      with q_g_2 have "q * j \<le> q * ((p - 1) div 2)"
  22.434 -        by (auto simp add: mult_le_cancel_left)
  22.435 -      with p_g_2 have "q * j div p \<le> q * ((p - 1) div 2) div p"
  22.436 -        by (auto simp add: zdiv_mono1)
  22.437 -      also from QRTEMP_axioms j_fact P_set_def have "... \<le> (q - 1) div 2"
  22.438 -        apply simp
  22.439 -        apply (insert aux2)
  22.440 -        apply (simp add: QRTEMP_def)
  22.441 -        done
  22.442 -      finally show "x \<le> (q - 1) div 2" using x by auto
  22.443 -    qed
  22.444 -    then show ?thesis by auto
  22.445 -  qed
  22.446 -  also have "... = (q * j) div p"
  22.447 -  proof -
  22.448 -    from j_fact P_set_def have "0 \<le> j" by auto
  22.449 -    with q_g_2 have "q * 0 \<le> q * j" by (auto simp only: mult_left_mono)
  22.450 -    then have "0 \<le> q * j" by auto
  22.451 -    then have "0 div p \<le> (q * j) div p"
  22.452 -      apply (rule_tac a = 0 in zdiv_mono1)
  22.453 -      apply (insert p_g_2, auto)
  22.454 -      done
  22.455 -    also have "0 div p = 0" by auto
  22.456 -    finally show ?thesis by (auto simp add: card_bdd_int_set_l_le)
  22.457 -  qed
  22.458 -  finally show "int (card (f1 j)) = q * j div p" .
  22.459 -qed
  22.460 -
  22.461 -lemma aux3b: "\<forall>j \<in> Q_set. int (card (f2 j)) = (p * j) div q"
  22.462 -proof
  22.463 -  fix j
  22.464 -  assume j_fact: "j \<in> Q_set"
  22.465 -  have "int (card (f2 j)) = int (card {y. y \<in> P_set & y \<le> (p * j) div q})"
  22.466 -  proof -
  22.467 -    have "finite (f2 j)"
  22.468 -    proof -
  22.469 -      have "(f2 j) \<subseteq> S" by (auto simp add: f2_def)
  22.470 -      with S_finite show ?thesis by (auto simp add: finite_subset)
  22.471 -    qed
  22.472 -    moreover have "inj_on (%(x,y). x) (f2 j)"
  22.473 -      by (auto simp add: f2_def inj_on_def)
  22.474 -    ultimately have "card ((%(x,y). x) ` (f2 j)) = card  (f2 j)"
  22.475 -      by (auto simp add: f2_def card_image)
  22.476 -    moreover have "((%(x,y). x) ` (f2 j)) = {y. y \<in> P_set & y \<le> (p * j) div q}"