src/HOL/Proofs/Extraction/Euclid.thy
changeset 39157 b98909faaea8
parent 37598 893dcabf0c04
child 41413 64cd30d6b0b8
equal deleted inserted replaced
39156:b4f18ac786fa 39157:b98909faaea8
       
     1 (*  Title:      HOL/Proofs/Extraction/Euclid.thy
       
     2     Author:     Markus Wenzel, TU Muenchen
       
     3     Author:     Freek Wiedijk, Radboud University Nijmegen
       
     4     Author:     Stefan Berghofer, TU Muenchen
       
     5 *)
       
     6 
       
     7 header {* Euclid's theorem *}
       
     8 
       
     9 theory Euclid
       
    10 imports "~~/src/HOL/Number_Theory/UniqueFactorization" Util Efficient_Nat
       
    11 begin
       
    12 
       
    13 text {*
       
    14 A constructive version of the proof of Euclid's theorem by
       
    15 Markus Wenzel and Freek Wiedijk \cite{Wenzel-Wiedijk-JAR2002}.
       
    16 *}
       
    17 
       
    18 lemma factor_greater_one1: "n = m * k \<Longrightarrow> m < n \<Longrightarrow> k < n \<Longrightarrow> Suc 0 < m"
       
    19   by (induct m) auto
       
    20 
       
    21 lemma factor_greater_one2: "n = m * k \<Longrightarrow> m < n \<Longrightarrow> k < n \<Longrightarrow> Suc 0 < k"
       
    22   by (induct k) auto
       
    23 
       
    24 lemma prod_mn_less_k:
       
    25   "(0::nat) < n ==> 0 < k ==> Suc 0 < m ==> m * n = k ==> n < k"
       
    26   by (induct m) auto
       
    27 
       
    28 lemma prime_eq: "prime (p::nat) = (1 < p \<and> (\<forall>m. m dvd p \<longrightarrow> 1 < m \<longrightarrow> m = p))"
       
    29   apply (simp add: prime_nat_def)
       
    30   apply (rule iffI)
       
    31   apply blast
       
    32   apply (erule conjE)
       
    33   apply (rule conjI)
       
    34   apply assumption
       
    35   apply (rule allI impI)+
       
    36   apply (erule allE)
       
    37   apply (erule impE)
       
    38   apply assumption
       
    39   apply (case_tac "m=0")
       
    40   apply simp
       
    41   apply (case_tac "m=Suc 0")
       
    42   apply simp
       
    43   apply simp
       
    44   done
       
    45 
       
    46 lemma prime_eq': "prime (p::nat) = (1 < p \<and> (\<forall>m k. p = m * k \<longrightarrow> 1 < m \<longrightarrow> m = p))"
       
    47   by (simp add: prime_eq dvd_def HOL.all_simps [symmetric] del: HOL.all_simps)
       
    48 
       
    49 lemma not_prime_ex_mk:
       
    50   assumes n: "Suc 0 < n"
       
    51   shows "(\<exists>m k. Suc 0 < m \<and> Suc 0 < k \<and> m < n \<and> k < n \<and> n = m * k) \<or> prime n"
       
    52 proof -
       
    53   {
       
    54     fix k
       
    55     from nat_eq_dec
       
    56     have "(\<exists>m<n. n = m * k) \<or> \<not> (\<exists>m<n. n = m * k)"
       
    57       by (rule search)
       
    58   }
       
    59   hence "(\<exists>k<n. \<exists>m<n. n = m * k) \<or> \<not> (\<exists>k<n. \<exists>m<n. n = m * k)"
       
    60     by (rule search)
       
    61   thus ?thesis
       
    62   proof
       
    63     assume "\<exists>k<n. \<exists>m<n. n = m * k"
       
    64     then obtain k m where k: "k<n" and m: "m<n" and nmk: "n = m * k"
       
    65       by iprover
       
    66     from nmk m k have "Suc 0 < m" by (rule factor_greater_one1)
       
    67     moreover from nmk m k have "Suc 0 < k" by (rule factor_greater_one2)
       
    68     ultimately show ?thesis using k m nmk by iprover
       
    69   next
       
    70     assume "\<not> (\<exists>k<n. \<exists>m<n. n = m * k)"
       
    71     hence A: "\<forall>k<n. \<forall>m<n. n \<noteq> m * k" by iprover
       
    72     have "\<forall>m k. n = m * k \<longrightarrow> Suc 0 < m \<longrightarrow> m = n"
       
    73     proof (intro allI impI)
       
    74       fix m k
       
    75       assume nmk: "n = m * k"
       
    76       assume m: "Suc 0 < m"
       
    77       from n m nmk have k: "0 < k"
       
    78         by (cases k) auto
       
    79       moreover from n have n: "0 < n" by simp
       
    80       moreover note m
       
    81       moreover from nmk have "m * k = n" by simp
       
    82       ultimately have kn: "k < n" by (rule prod_mn_less_k)
       
    83       show "m = n"
       
    84       proof (cases "k = Suc 0")
       
    85         case True
       
    86         with nmk show ?thesis by (simp only: mult_Suc_right)
       
    87       next
       
    88         case False
       
    89         from m have "0 < m" by simp
       
    90         moreover note n
       
    91         moreover from False n nmk k have "Suc 0 < k" by auto
       
    92         moreover from nmk have "k * m = n" by (simp only: mult_ac)
       
    93         ultimately have mn: "m < n" by (rule prod_mn_less_k)
       
    94         with kn A nmk show ?thesis by iprover
       
    95       qed
       
    96     qed
       
    97     with n have "prime n"
       
    98       by (simp only: prime_eq' One_nat_def simp_thms)
       
    99     thus ?thesis ..
       
   100   qed
       
   101 qed
       
   102 
       
   103 lemma dvd_factorial: "0 < m \<Longrightarrow> m \<le> n \<Longrightarrow> m dvd fact (n::nat)"
       
   104 proof (induct n rule: nat_induct)
       
   105   case 0
       
   106   then show ?case by simp
       
   107 next
       
   108   case (Suc n)
       
   109   from `m \<le> Suc n` show ?case
       
   110   proof (rule le_SucE)
       
   111     assume "m \<le> n"
       
   112     with `0 < m` have "m dvd fact n" by (rule Suc)
       
   113     then have "m dvd (fact n * Suc n)" by (rule dvd_mult2)
       
   114     then show ?thesis by (simp add: mult_commute)
       
   115   next
       
   116     assume "m = Suc n"
       
   117     then have "m dvd (fact n * Suc n)"
       
   118       by (auto intro: dvdI simp: mult_ac)
       
   119     then show ?thesis by (simp add: mult_commute)
       
   120   qed
       
   121 qed
       
   122 
       
   123 lemma dvd_prod [iff]: "n dvd (PROD m\<Colon>nat:#multiset_of (n # ns). m)"
       
   124   by (simp add: msetprod_Un msetprod_singleton)
       
   125 
       
   126 definition all_prime :: "nat list \<Rightarrow> bool" where
       
   127   "all_prime ps \<longleftrightarrow> (\<forall>p\<in>set ps. prime p)"
       
   128 
       
   129 lemma all_prime_simps:
       
   130   "all_prime []"
       
   131   "all_prime (p # ps) \<longleftrightarrow> prime p \<and> all_prime ps"
       
   132   by (simp_all add: all_prime_def)
       
   133 
       
   134 lemma all_prime_append:
       
   135   "all_prime (ps @ qs) \<longleftrightarrow> all_prime ps \<and> all_prime qs"
       
   136   by (simp add: all_prime_def ball_Un)
       
   137 
       
   138 lemma split_all_prime:
       
   139   assumes "all_prime ms" and "all_prime ns"
       
   140   shows "\<exists>qs. all_prime qs \<and> (PROD m\<Colon>nat:#multiset_of qs. m) =
       
   141     (PROD m\<Colon>nat:#multiset_of ms. m) * (PROD m\<Colon>nat:#multiset_of ns. m)" (is "\<exists>qs. ?P qs \<and> ?Q qs")
       
   142 proof -
       
   143   from assms have "all_prime (ms @ ns)"
       
   144     by (simp add: all_prime_append)
       
   145   moreover from assms have "(PROD m\<Colon>nat:#multiset_of (ms @ ns). m) =
       
   146     (PROD m\<Colon>nat:#multiset_of ms. m) * (PROD m\<Colon>nat:#multiset_of ns. m)"
       
   147     by (simp add: msetprod_Un)
       
   148   ultimately have "?P (ms @ ns) \<and> ?Q (ms @ ns)" ..
       
   149   then show ?thesis ..
       
   150 qed
       
   151 
       
   152 lemma all_prime_nempty_g_one:
       
   153   assumes "all_prime ps" and "ps \<noteq> []"
       
   154   shows "Suc 0 < (PROD m\<Colon>nat:#multiset_of ps. m)"
       
   155   using `ps \<noteq> []` `all_prime ps` unfolding One_nat_def [symmetric] by (induct ps rule: list_nonempty_induct)
       
   156     (simp_all add: all_prime_simps msetprod_singleton msetprod_Un prime_gt_1_nat less_1_mult del: One_nat_def)
       
   157 
       
   158 lemma factor_exists: "Suc 0 < n \<Longrightarrow> (\<exists>ps. all_prime ps \<and> (PROD m\<Colon>nat:#multiset_of ps. m) = n)"
       
   159 proof (induct n rule: nat_wf_ind)
       
   160   case (1 n)
       
   161   from `Suc 0 < n`
       
   162   have "(\<exists>m k. Suc 0 < m \<and> Suc 0 < k \<and> m < n \<and> k < n \<and> n = m * k) \<or> prime n"
       
   163     by (rule not_prime_ex_mk)
       
   164   then show ?case
       
   165   proof 
       
   166     assume "\<exists>m k. Suc 0 < m \<and> Suc 0 < k \<and> m < n \<and> k < n \<and> n = m * k"
       
   167     then obtain m k where m: "Suc 0 < m" and k: "Suc 0 < k" and mn: "m < n"
       
   168       and kn: "k < n" and nmk: "n = m * k" by iprover
       
   169     from mn and m have "\<exists>ps. all_prime ps \<and> (PROD m\<Colon>nat:#multiset_of ps. m) = m" by (rule 1)
       
   170     then obtain ps1 where "all_prime ps1" and prod_ps1_m: "(PROD m\<Colon>nat:#multiset_of ps1. m) = m"
       
   171       by iprover
       
   172     from kn and k have "\<exists>ps. all_prime ps \<and> (PROD m\<Colon>nat:#multiset_of ps. m) = k" by (rule 1)
       
   173     then obtain ps2 where "all_prime ps2" and prod_ps2_k: "(PROD m\<Colon>nat:#multiset_of ps2. m) = k"
       
   174       by iprover
       
   175     from `all_prime ps1` `all_prime ps2`
       
   176     have "\<exists>ps. all_prime ps \<and> (PROD m\<Colon>nat:#multiset_of ps. m) =
       
   177       (PROD m\<Colon>nat:#multiset_of ps1. m) * (PROD m\<Colon>nat:#multiset_of ps2. m)"
       
   178       by (rule split_all_prime)
       
   179     with prod_ps1_m prod_ps2_k nmk show ?thesis by simp
       
   180   next
       
   181     assume "prime n" then have "all_prime [n]" by (simp add: all_prime_simps)
       
   182     moreover have "(PROD m\<Colon>nat:#multiset_of [n]. m) = n" by (simp add: msetprod_singleton)
       
   183     ultimately have "all_prime [n] \<and> (PROD m\<Colon>nat:#multiset_of [n]. m) = n" ..
       
   184     then show ?thesis ..
       
   185   qed
       
   186 qed
       
   187 
       
   188 lemma prime_factor_exists:
       
   189   assumes N: "(1::nat) < n"
       
   190   shows "\<exists>p. prime p \<and> p dvd n"
       
   191 proof -
       
   192   from N obtain ps where "all_prime ps"
       
   193     and prod_ps: "n = (PROD m\<Colon>nat:#multiset_of ps. m)" using factor_exists
       
   194     by simp iprover
       
   195   with N have "ps \<noteq> []"
       
   196     by (auto simp add: all_prime_nempty_g_one msetprod_empty)
       
   197   then obtain p qs where ps: "ps = p # qs" by (cases ps) simp
       
   198   with `all_prime ps` have "prime p" by (simp add: all_prime_simps)
       
   199   moreover from `all_prime ps` ps prod_ps
       
   200   have "p dvd n" by (simp only: dvd_prod)
       
   201   ultimately show ?thesis by iprover
       
   202 qed
       
   203 
       
   204 text {*
       
   205 Euclid's theorem: there are infinitely many primes.
       
   206 *}
       
   207 
       
   208 lemma Euclid: "\<exists>p::nat. prime p \<and> n < p"
       
   209 proof -
       
   210   let ?k = "fact n + 1"
       
   211   have "1 < fact n + 1" by simp
       
   212   then obtain p where prime: "prime p" and dvd: "p dvd ?k" using prime_factor_exists by iprover
       
   213   have "n < p"
       
   214   proof -
       
   215     have "\<not> p \<le> n"
       
   216     proof
       
   217       assume pn: "p \<le> n"
       
   218       from `prime p` have "0 < p" by (rule prime_gt_0_nat)
       
   219       then have "p dvd fact n" using pn by (rule dvd_factorial)
       
   220       with dvd have "p dvd ?k - fact n" by (rule dvd_diff_nat)
       
   221       then have "p dvd 1" by simp
       
   222       with prime show False by auto
       
   223     qed
       
   224     then show ?thesis by simp
       
   225   qed
       
   226   with prime show ?thesis by iprover
       
   227 qed
       
   228 
       
   229 extract Euclid
       
   230 
       
   231 text {*
       
   232 The program extracted from the proof of Euclid's theorem looks as follows.
       
   233 @{thm [display] Euclid_def}
       
   234 The program corresponding to the proof of the factorization theorem is
       
   235 @{thm [display] factor_exists_def}
       
   236 *}
       
   237 
       
   238 instantiation nat :: default
       
   239 begin
       
   240 
       
   241 definition "default = (0::nat)"
       
   242 
       
   243 instance ..
       
   244 
       
   245 end
       
   246 
       
   247 instantiation list :: (type) default
       
   248 begin
       
   249 
       
   250 definition "default = []"
       
   251 
       
   252 instance ..
       
   253 
       
   254 end
       
   255 
       
   256 primrec iterate :: "nat \<Rightarrow> ('a \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> 'a list" where
       
   257   "iterate 0 f x = []"
       
   258   | "iterate (Suc n) f x = (let y = f x in y # iterate n f y)"
       
   259 
       
   260 lemma "factor_exists 1007 = [53, 19]" by eval
       
   261 lemma "factor_exists 567 = [7, 3, 3, 3, 3]" by eval
       
   262 lemma "factor_exists 345 = [23, 5, 3]" by eval
       
   263 lemma "factor_exists 999 = [37, 3, 3, 3]" by eval
       
   264 lemma "factor_exists 876 = [73, 3, 2, 2]" by eval
       
   265 
       
   266 lemma "iterate 4 Euclid 0 = [2, 3, 7, 71]" by eval
       
   267 
       
   268 consts_code
       
   269   default ("(error \"default\")")
       
   270 
       
   271 lemma "factor_exists 1007 = [53, 19]" by evaluation
       
   272 lemma "factor_exists 567 = [7, 3, 3, 3, 3]" by evaluation
       
   273 lemma "factor_exists 345 = [23, 5, 3]" by evaluation
       
   274 lemma "factor_exists 999 = [37, 3, 3, 3]" by evaluation
       
   275 lemma "factor_exists 876 = [73, 3, 2, 2]" by evaluation
       
   276 
       
   277 lemma "iterate 4 Euclid 0 = [2, 3, 7, 71]" by evaluation
       
   278 
       
   279 end