src/HOL/Number_Theory/UniqueFactorization.thy
changeset 63534 523b488b15c9
parent 62430 9527ff088c15
equal deleted inserted replaced
63525:f01d1e393f3f 63534:523b488b15c9
    10 
    10 
    11 theory UniqueFactorization
    11 theory UniqueFactorization
    12 imports Cong "~~/src/HOL/Library/Multiset"
    12 imports Cong "~~/src/HOL/Library/Multiset"
    13 begin
    13 begin
    14 
    14 
    15 (* As a simp or intro rule,
       
    16 
       
    17      prime p \<Longrightarrow> p > 0
       
    18 
       
    19    wreaks havoc here. When the premise includes \<forall>x \<in># M. prime x, it
       
    20    leads to the backchaining
       
    21 
       
    22      x > 0
       
    23      prime x
       
    24      x \<in># M   which is, unfortunately,
       
    25      count M x > 0
       
    26 *)
       
    27 
       
    28 (* Here is a version of set product for multisets. Is it worth moving
       
    29    to multiset.thy? If so, one should similarly define msetsum for abelian
       
    30    semirings, using of_nat. Also, is it worth developing bounded quantifiers
       
    31    "\<forall>i \<in># M. P i"?
       
    32 *)
       
    33 
       
    34 
       
    35 subsection \<open>Unique factorization: multiset version\<close>
       
    36 
       
    37 lemma multiset_prime_factorization_exists:
       
    38   "n > 0 \<Longrightarrow> (\<exists>M. (\<forall>p::nat \<in> set_mset M. prime p) \<and> n = (\<Prod>i \<in># M. i))"
       
    39 proof (induct n rule: nat_less_induct)
       
    40   fix n :: nat
       
    41   assume ih: "\<forall>m < n. 0 < m \<longrightarrow> (\<exists>M. (\<forall>p\<in>set_mset M. prime p) \<and> m = (\<Prod>i \<in># M. i))"
       
    42   assume "n > 0"
       
    43   then consider "n = 1" | "n > 1" "prime n" | "n > 1" "\<not> prime n"
       
    44     by arith
       
    45   then show "\<exists>M. (\<forall>p \<in> set_mset M. prime p) \<and> n = (\<Prod>i\<in>#M. i)"
       
    46   proof cases
       
    47     case 1
       
    48     then have "(\<forall>p\<in>set_mset {#}. prime p) \<and> n = (\<Prod>i \<in># {#}. i)"
       
    49       by auto
       
    50     then show ?thesis ..
       
    51   next
       
    52     case 2
       
    53     then have "(\<forall>p\<in>set_mset {#n#}. prime p) \<and> n = (\<Prod>i \<in># {#n#}. i)"
       
    54       by auto
       
    55     then show ?thesis ..
       
    56   next
       
    57     case 3
       
    58     with not_prime_eq_prod_nat
       
    59     obtain m k where n: "n = m * k" "1 < m" "m < n" "1 < k" "k < n"
       
    60       by blast
       
    61     with ih obtain Q R where "(\<forall>p \<in> set_mset Q. prime p) \<and> m = (\<Prod>i\<in>#Q. i)"
       
    62         and "(\<forall>p\<in>set_mset R. prime p) \<and> k = (\<Prod>i\<in>#R. i)"
       
    63       by blast
       
    64     then have "(\<forall>p\<in>set_mset (Q + R). prime p) \<and> n = (\<Prod>i \<in># Q + R. i)"
       
    65       by (auto simp add: n msetprod_Un)
       
    66     then show ?thesis ..
       
    67   qed
       
    68 qed
       
    69 
       
    70 lemma multiset_prime_factorization_unique_aux:
       
    71   fixes a :: nat
       
    72   assumes "\<forall>p\<in>set_mset M. prime p"
       
    73     and "\<forall>p\<in>set_mset N. prime p"
       
    74     and "(\<Prod>i \<in># M. i) dvd (\<Prod>i \<in># N. i)"
       
    75   shows "count M a \<le> count N a"
       
    76 proof (cases "a \<in> set_mset M")
       
    77   case True
       
    78   with assms have a: "prime a"
       
    79     by auto
       
    80   with True have "a ^ count M a dvd (\<Prod>i \<in># M. i)"
       
    81     by (auto simp add: msetprod_multiplicity)
       
    82   also have "\<dots> dvd (\<Prod>i \<in># N. i)"
       
    83     by (rule assms)
       
    84   also have "\<dots> = (\<Prod>i \<in> set_mset N. i ^ count N i)"
       
    85     by (simp add: msetprod_multiplicity)
       
    86   also have "\<dots> = a ^ count N a * (\<Prod>i \<in> (set_mset N - {a}). i ^ count N i)"
       
    87   proof (cases "a \<in> set_mset N")
       
    88     case True
       
    89     then have b: "set_mset N = {a} \<union> (set_mset N - {a})"
       
    90       by auto
       
    91     then show ?thesis
       
    92       by (subst (1) b, subst setprod.union_disjoint, auto)
       
    93   next
       
    94     case False
       
    95     then show ?thesis
       
    96       by (auto simp add: not_in_iff)
       
    97   qed
       
    98   finally have "a ^ count M a dvd a ^ count N a * (\<Prod>i \<in> (set_mset N - {a}). i ^ count N i)" .
       
    99   moreover
       
   100   have "coprime (a ^ count M a) (\<Prod>i \<in> (set_mset N - {a}). i ^ count N i)"
       
   101     apply (subst gcd.commute)
       
   102     apply (rule setprod_coprime)
       
   103     apply (rule primes_imp_powers_coprime_nat)
       
   104     using assms True
       
   105     apply auto
       
   106     done
       
   107   ultimately have "a ^ count M a dvd a ^ count N a"
       
   108     by (elim coprime_dvd_mult)
       
   109   with a show ?thesis
       
   110     using power_dvd_imp_le prime_def by blast
       
   111 next
       
   112   case False
       
   113   then show ?thesis
       
   114     by (auto simp add: not_in_iff)
       
   115 qed
       
   116 
       
   117 lemma multiset_prime_factorization_unique:
       
   118   assumes "\<forall>p::nat \<in> set_mset M. prime p"
       
   119     and "\<forall>p \<in> set_mset N. prime p"
       
   120     and "(\<Prod>i \<in># M. i) = (\<Prod>i \<in># N. i)"
       
   121   shows "M = N"
       
   122 proof -
       
   123   have "count M a = count N a" for a
       
   124   proof -
       
   125     from assms have "count M a \<le> count N a"
       
   126       by (intro multiset_prime_factorization_unique_aux, auto)
       
   127     moreover from assms have "count N a \<le> count M a"
       
   128       by (intro multiset_prime_factorization_unique_aux, auto)
       
   129     ultimately show ?thesis
       
   130       by auto
       
   131   qed
       
   132   then show ?thesis
       
   133     by (simp add: multiset_eq_iff)
       
   134 qed
       
   135 
       
   136 definition multiset_prime_factorization :: "nat \<Rightarrow> nat multiset"
       
   137 where
       
   138   "multiset_prime_factorization n =
       
   139     (if n > 0
       
   140      then THE M. (\<forall>p \<in> set_mset M. prime p) \<and> n = (\<Prod>i \<in># M. i)
       
   141      else {#})"
       
   142 
       
   143 lemma multiset_prime_factorization: "n > 0 \<Longrightarrow>
       
   144     (\<forall>p \<in> set_mset (multiset_prime_factorization n). prime p) \<and>
       
   145        n = (\<Prod>i \<in># (multiset_prime_factorization n). i)"
       
   146   apply (unfold multiset_prime_factorization_def)
       
   147   apply clarsimp
       
   148   apply (frule multiset_prime_factorization_exists)
       
   149   apply clarify
       
   150   apply (rule theI)
       
   151   apply (insert multiset_prime_factorization_unique)
       
   152   apply auto
       
   153   done
       
   154 
       
   155 
       
   156 subsection \<open>Prime factors and multiplicity for nat and int\<close>
       
   157 
       
   158 class unique_factorization =
       
   159   fixes multiplicity :: "'a \<Rightarrow> 'a \<Rightarrow> nat"
       
   160     and prime_factors :: "'a \<Rightarrow> 'a set"
       
   161 
       
   162 text \<open>Definitions for the natural numbers.\<close>
       
   163 instantiation nat :: unique_factorization
       
   164 begin
       
   165 
       
   166 definition multiplicity_nat :: "nat \<Rightarrow> nat \<Rightarrow> nat"
       
   167   where "multiplicity_nat p n = count (multiset_prime_factorization n) p"
       
   168 
       
   169 definition prime_factors_nat :: "nat \<Rightarrow> nat set"
       
   170   where "prime_factors_nat n = set_mset (multiset_prime_factorization n)"
       
   171 
       
   172 instance ..
       
   173 
       
   174 end
    15 end
   175 
       
   176 text \<open>Definitions for the integers.\<close>
       
   177 instantiation int :: unique_factorization
       
   178 begin
       
   179 
       
   180 definition multiplicity_int :: "int \<Rightarrow> int \<Rightarrow> nat"
       
   181   where "multiplicity_int p n = multiplicity (nat p) (nat n)"
       
   182 
       
   183 definition prime_factors_int :: "int \<Rightarrow> int set"
       
   184   where "prime_factors_int n = int ` (prime_factors (nat n))"
       
   185 
       
   186 instance ..
       
   187 
       
   188 end
       
   189 
       
   190 
       
   191 subsection \<open>Set up transfer\<close>
       
   192 
       
   193 lemma transfer_nat_int_prime_factors: "prime_factors (nat n) = nat ` prime_factors n"
       
   194   unfolding prime_factors_int_def
       
   195   apply auto
       
   196   apply (subst transfer_int_nat_set_return_embed)
       
   197   apply assumption
       
   198   done
       
   199 
       
   200 lemma transfer_nat_int_prime_factors_closure: "n \<ge> 0 \<Longrightarrow> nat_set (prime_factors n)"
       
   201   by (auto simp add: nat_set_def prime_factors_int_def)
       
   202 
       
   203 lemma transfer_nat_int_multiplicity:
       
   204   "p \<ge> 0 \<Longrightarrow> n \<ge> 0 \<Longrightarrow> multiplicity (nat p) (nat n) = multiplicity p n"
       
   205   by (auto simp add: multiplicity_int_def)
       
   206 
       
   207 declare transfer_morphism_nat_int[transfer add return:
       
   208   transfer_nat_int_prime_factors transfer_nat_int_prime_factors_closure
       
   209   transfer_nat_int_multiplicity]
       
   210 
       
   211 lemma transfer_int_nat_prime_factors: "prime_factors (int n) = int ` prime_factors n"
       
   212   unfolding prime_factors_int_def by auto
       
   213 
       
   214 lemma transfer_int_nat_prime_factors_closure: "is_nat n \<Longrightarrow> nat_set (prime_factors n)"
       
   215   by (simp only: transfer_nat_int_prime_factors_closure is_nat_def)
       
   216 
       
   217 lemma transfer_int_nat_multiplicity: "multiplicity (int p) (int n) = multiplicity p n"
       
   218   by (auto simp add: multiplicity_int_def)
       
   219 
       
   220 declare transfer_morphism_int_nat[transfer add return:
       
   221   transfer_int_nat_prime_factors transfer_int_nat_prime_factors_closure
       
   222   transfer_int_nat_multiplicity]
       
   223 
       
   224 
       
   225 subsection \<open>Properties of prime factors and multiplicity for nat and int\<close>
       
   226 
       
   227 lemma prime_factors_ge_0_int [elim]:
       
   228   fixes n :: int
       
   229   shows "p \<in> prime_factors n \<Longrightarrow> p \<ge> 0"
       
   230   unfolding prime_factors_int_def by auto
       
   231 
       
   232 lemma prime_factors_prime_nat [intro]:
       
   233   fixes n :: nat
       
   234   shows "p \<in> prime_factors n \<Longrightarrow> prime p"
       
   235   apply (cases "n = 0")
       
   236   apply (simp add: prime_factors_nat_def multiset_prime_factorization_def)
       
   237   apply (auto simp add: prime_factors_nat_def multiset_prime_factorization)
       
   238   done
       
   239 
       
   240 lemma prime_factors_prime_int [intro]:
       
   241   fixes n :: int
       
   242   assumes "n \<ge> 0" and "p \<in> prime_factors n"
       
   243   shows "prime p"
       
   244   apply (rule prime_factors_prime_nat [transferred, of n p, simplified])
       
   245   using assms apply auto
       
   246   done
       
   247 
       
   248 lemma prime_factors_gt_0_nat:
       
   249   fixes p :: nat
       
   250   shows "p \<in> prime_factors x \<Longrightarrow> p > 0"
       
   251     using prime_factors_prime_nat by force
       
   252 
       
   253 lemma prime_factors_gt_0_int:
       
   254   shows "x \<ge> 0 \<Longrightarrow> p \<in> prime_factors x \<Longrightarrow> int p > (0::int)"
       
   255     by (simp add: prime_factors_gt_0_nat)
       
   256 
       
   257 lemma prime_factors_finite_nat [iff]:
       
   258   fixes n :: nat
       
   259   shows "finite (prime_factors n)"
       
   260   unfolding prime_factors_nat_def by auto
       
   261 
       
   262 lemma prime_factors_finite_int [iff]:
       
   263   fixes n :: int
       
   264   shows "finite (prime_factors n)"
       
   265   unfolding prime_factors_int_def by auto
       
   266 
       
   267 lemma prime_factors_altdef_nat:
       
   268   fixes n :: nat
       
   269   shows "prime_factors n = {p. multiplicity p n > 0}"
       
   270   by (force simp add: prime_factors_nat_def multiplicity_nat_def)
       
   271 
       
   272 lemma prime_factors_altdef_int:
       
   273   fixes n :: int
       
   274   shows "prime_factors n = {p. p \<ge> 0 \<and> multiplicity p n > 0}"
       
   275   apply (unfold prime_factors_int_def multiplicity_int_def)
       
   276   apply (subst prime_factors_altdef_nat)
       
   277   apply (auto simp add: image_def)
       
   278   done
       
   279 
       
   280 lemma prime_factorization_nat:
       
   281   fixes n :: nat
       
   282   shows "n > 0 \<Longrightarrow> n = (\<Prod>p \<in> prime_factors n. p ^ multiplicity p n)"
       
   283   apply (frule multiset_prime_factorization)
       
   284   apply (simp add: prime_factors_nat_def multiplicity_nat_def msetprod_multiplicity)
       
   285   done
       
   286 
       
   287 lemma prime_factorization_int:
       
   288   fixes n :: int
       
   289   assumes "n > 0"
       
   290   shows "n = (\<Prod>p \<in> prime_factors n. p ^ multiplicity p n)"
       
   291   apply (rule prime_factorization_nat [transferred, of n])
       
   292   using assms apply auto
       
   293   done
       
   294 
       
   295 lemma prime_factorization_unique_nat:
       
   296   fixes f :: "nat \<Rightarrow> _"
       
   297   assumes S_eq: "S = {p. 0 < f p}"
       
   298     and "finite S"
       
   299     and S: "\<forall>p\<in>S. prime p" "n = (\<Prod>p\<in>S. p ^ f p)"
       
   300   shows "S = prime_factors n \<and> (\<forall>p. f p = multiplicity p n)"
       
   301 proof -
       
   302   from assms have "f \<in> multiset"
       
   303     by (auto simp add: multiset_def)
       
   304   moreover from assms have "n > 0" 
       
   305     by (auto intro: prime_gt_0_nat)
       
   306   ultimately have "multiset_prime_factorization n = Abs_multiset f"
       
   307     apply (unfold multiset_prime_factorization_def)
       
   308     apply (subst if_P, assumption)
       
   309     apply (rule the1_equality)
       
   310     apply (rule ex_ex1I)
       
   311     apply (rule multiset_prime_factorization_exists, assumption)
       
   312     apply (rule multiset_prime_factorization_unique)
       
   313     apply force
       
   314     apply force
       
   315     apply force
       
   316     using S S_eq  apply (simp add: set_mset_def msetprod_multiplicity)
       
   317     done
       
   318   with \<open>f \<in> multiset\<close> have "count (multiset_prime_factorization n) = f"
       
   319     by simp
       
   320   with S_eq show ?thesis
       
   321     by (simp add: set_mset_def multiset_def prime_factors_nat_def multiplicity_nat_def)
       
   322 qed
       
   323 
       
   324 lemma prime_factors_characterization_nat:
       
   325   "S = {p. 0 < f (p::nat)} \<Longrightarrow>
       
   326     finite S \<Longrightarrow> \<forall>p\<in>S. prime p \<Longrightarrow> n = (\<Prod>p\<in>S. p ^ f p) \<Longrightarrow> prime_factors n = S"
       
   327   by (rule prime_factorization_unique_nat [THEN conjunct1, symmetric])
       
   328 
       
   329 lemma prime_factors_characterization'_nat:
       
   330   "finite {p. 0 < f (p::nat)} \<Longrightarrow>
       
   331     (\<forall>p. 0 < f p \<longrightarrow> prime p) \<Longrightarrow>
       
   332       prime_factors (\<Prod>p | 0 < f p. p ^ f p) = {p. 0 < f p}"
       
   333   by (rule prime_factors_characterization_nat) auto
       
   334 
       
   335 (* A minor glitch:*)
       
   336 thm prime_factors_characterization'_nat
       
   337     [where f = "\<lambda>x. f (int (x::nat))",
       
   338       transferred direction: nat "op \<le> (0::int)", rule_format]
       
   339 
       
   340 (*
       
   341   Transfer isn't smart enough to know that the "0 < f p" should
       
   342   remain a comparison between nats. But the transfer still works.
       
   343 *)
       
   344 
       
   345 lemma primes_characterization'_int [rule_format]:
       
   346   "finite {p. p \<ge> 0 \<and> 0 < f (p::int)} \<Longrightarrow> \<forall>p. 0 < f p \<longrightarrow> prime p \<Longrightarrow>
       
   347       prime_factors (\<Prod>p | p \<ge> 0 \<and> 0 < f p. p ^ f p) = {p. p \<ge> 0 \<and> 0 < f p}"
       
   348   using prime_factors_characterization'_nat
       
   349     [where f = "\<lambda>x. f (int (x::nat))",
       
   350     transferred direction: nat "op \<le> (0::int)"]
       
   351   by auto
       
   352 
       
   353 lemma prime_factors_characterization_int:
       
   354   "S = {p. 0 < f (p::int)} \<Longrightarrow> finite S \<Longrightarrow>
       
   355     \<forall>p\<in>S. prime (nat p) \<Longrightarrow> n = (\<Prod>p\<in>S. p ^ f p) \<Longrightarrow> prime_factors n = S"
       
   356   apply simp
       
   357   apply (subgoal_tac "{p. 0 < f p} = {p. 0 \<le> p \<and> 0 < f p}")
       
   358   apply (simp only:)
       
   359   apply (subst primes_characterization'_int)
       
   360   apply simp_all
       
   361   apply (metis nat_int)
       
   362   apply (metis le_cases nat_le_0 zero_not_prime_nat)
       
   363   done
       
   364 
       
   365 lemma multiplicity_characterization_nat:
       
   366   "S = {p. 0 < f (p::nat)} \<Longrightarrow> finite S \<Longrightarrow> \<forall>p\<in>S. prime p \<Longrightarrow>
       
   367     n = (\<Prod>p\<in>S. p ^ f p) \<Longrightarrow> multiplicity p n = f p"
       
   368   apply (frule prime_factorization_unique_nat [THEN conjunct2, rule_format, symmetric])
       
   369   apply auto
       
   370   done
       
   371 
       
   372 lemma multiplicity_characterization'_nat: "finite {p. 0 < f (p::nat)} \<longrightarrow>
       
   373     (\<forall>p. 0 < f p \<longrightarrow> prime p) \<longrightarrow>
       
   374       multiplicity p (\<Prod>p | 0 < f p. p ^ f p) = f p"
       
   375   apply (intro impI)
       
   376   apply (rule multiplicity_characterization_nat)
       
   377   apply auto
       
   378   done
       
   379 
       
   380 lemma multiplicity_characterization'_int [rule_format]:
       
   381   "finite {p. p \<ge> 0 \<and> 0 < f (p::int)} \<Longrightarrow>
       
   382     (\<forall>p. 0 < f p \<longrightarrow> prime p) \<Longrightarrow> p \<ge> 0 \<Longrightarrow>
       
   383       multiplicity p (\<Prod>p | p \<ge> 0 \<and> 0 < f p. p ^ f p) = f p"
       
   384   apply (insert multiplicity_characterization'_nat
       
   385     [where f = "\<lambda>x. f (int (x::nat))",
       
   386       transferred direction: nat "op \<le> (0::int)", rule_format])
       
   387   apply auto
       
   388   done
       
   389 
       
   390 lemma multiplicity_characterization_int: "S = {p. 0 < f (p::int)} \<Longrightarrow>
       
   391     finite S \<Longrightarrow> \<forall>p\<in>S. prime (nat p) \<Longrightarrow> n = (\<Prod>p\<in>S. p ^ f p) \<Longrightarrow>
       
   392       p \<ge> 0 \<Longrightarrow> multiplicity p n = f p"
       
   393   apply simp
       
   394   apply (subgoal_tac "{p. 0 < f p} = {p. 0 \<le> p \<and> 0 < f p}")
       
   395   apply (simp only:)
       
   396   apply (subst multiplicity_characterization'_int)
       
   397   apply simp_all
       
   398   apply (metis nat_int)
       
   399   apply (metis le_cases nat_le_0 zero_not_prime_nat)
       
   400   done
       
   401 
       
   402 lemma multiplicity_zero_nat [simp]: "multiplicity (p::nat) 0 = 0"
       
   403   by (simp add: multiplicity_nat_def multiset_prime_factorization_def)
       
   404 
       
   405 lemma multiplicity_zero_int [simp]: "multiplicity (p::int) 0 = 0"
       
   406   by (simp add: multiplicity_int_def)
       
   407 
       
   408 lemma multiplicity_one_nat': "multiplicity p (1::nat) = 0"
       
   409   by (subst multiplicity_characterization_nat [where f = "\<lambda>x. 0"], auto)
       
   410 
       
   411 lemma multiplicity_one_nat [simp]: "multiplicity p (Suc 0) = 0"
       
   412   by (metis One_nat_def multiplicity_one_nat')
       
   413 
       
   414 lemma multiplicity_one_int [simp]: "multiplicity p (1::int) = 0"
       
   415   by (metis multiplicity_int_def multiplicity_one_nat' transfer_nat_int_numerals(2))
       
   416 
       
   417 lemma multiplicity_prime_nat [simp]: "prime p \<Longrightarrow> multiplicity p p = 1"
       
   418   apply (subst multiplicity_characterization_nat [where f = "\<lambda>q. if q = p then 1 else 0"])
       
   419   apply auto
       
   420   apply (metis (full_types) less_not_refl)
       
   421   done
       
   422 
       
   423 lemma multiplicity_prime_power_nat [simp]: "prime p \<Longrightarrow> multiplicity p (p ^ n) = n"
       
   424   apply (cases "n = 0")
       
   425   apply auto
       
   426   apply (subst multiplicity_characterization_nat [where f = "\<lambda>q. if q = p then n else 0"])
       
   427   apply auto
       
   428   apply (metis (full_types) less_not_refl)
       
   429   done
       
   430 
       
   431 lemma multiplicity_prime_power_int [simp]: "prime p \<Longrightarrow> multiplicity p (int p ^ n) = n"
       
   432   by (metis multiplicity_prime_power_nat of_nat_power transfer_int_nat_multiplicity)
       
   433 
       
   434 lemma multiplicity_nonprime_nat [simp]:
       
   435   fixes p n :: nat
       
   436   shows "\<not> prime p \<Longrightarrow> multiplicity p n = 0"
       
   437   apply (cases "n = 0")
       
   438   apply auto
       
   439   apply (frule multiset_prime_factorization)
       
   440   apply (auto simp add: multiplicity_nat_def count_eq_zero_iff)
       
   441   done
       
   442 
       
   443 lemma multiplicity_not_factor_nat [simp]:
       
   444   fixes p n :: nat
       
   445   shows "p \<notin> prime_factors n \<Longrightarrow> multiplicity p n = 0"
       
   446   apply (subst (asm) prime_factors_altdef_nat)
       
   447   apply auto
       
   448   done
       
   449 
       
   450 lemma multiplicity_not_factor_int [simp]:
       
   451   fixes n :: int
       
   452   shows "p \<ge> 0 \<Longrightarrow> p \<notin> prime_factors n \<Longrightarrow> multiplicity p n = 0"
       
   453   apply (subst (asm) prime_factors_altdef_int)
       
   454   apply auto
       
   455   done
       
   456 
       
   457 (*FIXME: messy*)
       
   458 lemma multiplicity_product_aux_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow>
       
   459     (prime_factors k) \<union> (prime_factors l) = prime_factors (k * l) \<and>
       
   460     (\<forall>p. multiplicity p k + multiplicity p l = multiplicity p (k * l))"
       
   461   apply (rule prime_factorization_unique_nat)
       
   462   apply (simp only: prime_factors_altdef_nat)
       
   463   apply auto
       
   464   apply (subst power_add)
       
   465   apply (subst setprod.distrib)
       
   466   apply (rule arg_cong2 [where f = "\<lambda>x y. x*y"])
       
   467   apply (subgoal_tac "prime_factors k \<union> prime_factors l = prime_factors k \<union>
       
   468       (prime_factors l - prime_factors k)")
       
   469   apply (erule ssubst)
       
   470   apply (subst setprod.union_disjoint)
       
   471   apply auto
       
   472   apply (metis One_nat_def nat_mult_1_right prime_factorization_nat setprod.neutral_const)
       
   473   apply (subgoal_tac "prime_factors k \<union> prime_factors l = prime_factors l \<union>
       
   474       (prime_factors k - prime_factors l)")
       
   475   apply (erule ssubst)
       
   476   apply (subst setprod.union_disjoint)
       
   477   apply auto
       
   478   apply (subgoal_tac "(\<Prod>p\<in>prime_factors k - prime_factors l. p ^ multiplicity p l) =
       
   479       (\<Prod>p\<in>prime_factors k - prime_factors l. 1)")
       
   480   apply auto
       
   481   apply (metis One_nat_def nat_mult_1_right prime_factorization_nat setprod.neutral_const)
       
   482   done
       
   483 
       
   484 (* transfer doesn't have the same problem here with the right
       
   485    choice of rules. *)
       
   486 
       
   487 lemma multiplicity_product_aux_int:
       
   488   assumes "(k::int) > 0" and "l > 0"
       
   489   shows "prime_factors k \<union> prime_factors l = prime_factors (k * l) \<and>
       
   490     (\<forall>p \<ge> 0. multiplicity p k + multiplicity p l = multiplicity p (k * l))"
       
   491   apply (rule multiplicity_product_aux_nat [transferred, of l k])
       
   492   using assms apply auto
       
   493   done
       
   494 
       
   495 lemma prime_factors_product_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> prime_factors (k * l) =
       
   496     prime_factors k \<union> prime_factors l"
       
   497   by (rule multiplicity_product_aux_nat [THEN conjunct1, symmetric])
       
   498 
       
   499 lemma prime_factors_product_int: "(k::int) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> prime_factors (k * l) =
       
   500     prime_factors k \<union> prime_factors l"
       
   501   by (rule multiplicity_product_aux_int [THEN conjunct1, symmetric])
       
   502 
       
   503 lemma multiplicity_product_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> multiplicity p (k * l) =
       
   504     multiplicity p k + multiplicity p l"
       
   505   by (rule multiplicity_product_aux_nat [THEN conjunct2, rule_format, symmetric])
       
   506 
       
   507 lemma multiplicity_product_int: "(k::int) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> p \<ge> 0 \<Longrightarrow>
       
   508     multiplicity p (k * l) = multiplicity p k + multiplicity p l"
       
   509   by (rule multiplicity_product_aux_int [THEN conjunct2, rule_format, symmetric])
       
   510 
       
   511 lemma multiplicity_setprod_nat: "finite S \<Longrightarrow> \<forall>x\<in>S. f x > 0 \<Longrightarrow>
       
   512     multiplicity (p::nat) (\<Prod>x \<in> S. f x) = (\<Sum>x \<in> S. multiplicity p (f x))"
       
   513   apply (induct set: finite)
       
   514   apply auto
       
   515   apply (subst multiplicity_product_nat)
       
   516   apply auto
       
   517   done
       
   518 
       
   519 (* Transfer is delicate here for two reasons: first, because there is
       
   520    an implicit quantifier over functions (f), and, second, because the
       
   521    product over the multiplicity should not be translated to an integer
       
   522    product.
       
   523 
       
   524    The way to handle the first is to use quantifier rules for functions.
       
   525    The way to handle the second is to turn off the offending rule.
       
   526 *)
       
   527 
       
   528 lemma transfer_nat_int_sum_prod_closure3: "(\<Sum>x \<in> A. int (f x)) \<ge> 0" "(\<Prod>x \<in> A. int (f x)) \<ge> 0"
       
   529   apply (rule setsum_nonneg; auto)
       
   530   apply (rule setprod_nonneg; auto)
       
   531   done
       
   532 
       
   533 declare transfer_morphism_nat_int[transfer
       
   534   add return: transfer_nat_int_sum_prod_closure3
       
   535   del: transfer_nat_int_sum_prod2 (1)]
       
   536 
       
   537 lemma multiplicity_setprod_int: "p \<ge> 0 \<Longrightarrow> finite S \<Longrightarrow> \<forall>x\<in>S. f x > 0 \<Longrightarrow>
       
   538     multiplicity (p::int) (\<Prod>x \<in> S. f x) = (\<Sum>x \<in> S. multiplicity p (f x))"
       
   539   apply (frule multiplicity_setprod_nat
       
   540     [where f = "\<lambda>x. nat(int(nat(f x)))",
       
   541       transferred direction: nat "op \<le> (0::int)"])
       
   542   apply auto
       
   543   apply (subst (asm) setprod.cong)
       
   544   apply (rule refl)
       
   545   apply (rule if_P)
       
   546   apply auto
       
   547   apply (rule setsum.cong)
       
   548   apply auto
       
   549   done
       
   550 
       
   551 declare transfer_morphism_nat_int[transfer
       
   552   add return: transfer_nat_int_sum_prod2 (1)]
       
   553 
       
   554 lemma multiplicity_prod_prime_powers_nat:
       
   555     "finite S \<Longrightarrow> \<forall>p\<in>S. prime (p::nat) \<Longrightarrow>
       
   556        multiplicity p (\<Prod>p \<in> S. p ^ f p) = (if p \<in> S then f p else 0)"
       
   557   apply (subgoal_tac "(\<Prod>p \<in> S. p ^ f p) = (\<Prod>p \<in> S. p ^ (\<lambda>x. if x \<in> S then f x else 0) p)")
       
   558   apply (erule ssubst)
       
   559   apply (subst multiplicity_characterization_nat)
       
   560   prefer 5 apply (rule refl)
       
   561   apply (rule refl)
       
   562   apply auto
       
   563   apply (subst setprod.mono_neutral_right)
       
   564   apply assumption
       
   565   prefer 3
       
   566   apply (rule setprod.cong)
       
   567   apply (rule refl)
       
   568   apply auto
       
   569   done
       
   570 
       
   571 (* Here the issue with transfer is the implicit quantifier over S *)
       
   572 
       
   573 lemma multiplicity_prod_prime_powers_int:
       
   574     "(p::int) \<ge> 0 \<Longrightarrow> finite S \<Longrightarrow> \<forall>p\<in>S. prime (nat p) \<Longrightarrow>
       
   575        multiplicity p (\<Prod>p \<in> S. p ^ f p) = (if p \<in> S then f p else 0)"
       
   576   apply (subgoal_tac "int ` nat ` S = S")
       
   577   apply (frule multiplicity_prod_prime_powers_nat
       
   578     [where f = "\<lambda>x. f(int x)" and S = "nat ` S", transferred])
       
   579   apply auto
       
   580   apply (metis linear nat_0_iff zero_not_prime_nat)
       
   581   apply (metis (full_types) image_iff int_nat_eq less_le less_linear nat_0_iff zero_not_prime_nat)
       
   582   done
       
   583 
       
   584 lemma multiplicity_distinct_prime_power_nat:
       
   585     "prime p \<Longrightarrow> prime q \<Longrightarrow> p \<noteq> q \<Longrightarrow> multiplicity p (q ^ n) = 0"
       
   586   apply (subgoal_tac "q ^ n = setprod (\<lambda>x. x ^ n) {q}")
       
   587   apply (erule ssubst)
       
   588   apply (subst multiplicity_prod_prime_powers_nat)
       
   589   apply auto
       
   590   done
       
   591 
       
   592 lemma multiplicity_distinct_prime_power_int:
       
   593     "prime p \<Longrightarrow> prime q \<Longrightarrow> p \<noteq> q \<Longrightarrow> multiplicity p (int q ^ n) = 0"
       
   594   by (metis multiplicity_distinct_prime_power_nat of_nat_power transfer_int_nat_multiplicity)
       
   595 
       
   596 lemma dvd_multiplicity_nat:
       
   597   fixes x y :: nat
       
   598   shows "0 < y \<Longrightarrow> x dvd y \<Longrightarrow> multiplicity p x \<le> multiplicity p y"
       
   599   apply (cases "x = 0")
       
   600   apply (auto simp add: dvd_def multiplicity_product_nat)
       
   601   done
       
   602 
       
   603 lemma dvd_multiplicity_int:
       
   604   fixes p x y :: int
       
   605   shows "0 < y \<Longrightarrow> 0 \<le> x \<Longrightarrow> x dvd y \<Longrightarrow> p \<ge> 0 \<Longrightarrow> multiplicity p x \<le> multiplicity p y"
       
   606   apply (cases "x = 0")
       
   607   apply (auto simp add: dvd_def)
       
   608   apply (subgoal_tac "0 < k")
       
   609   apply (auto simp add: multiplicity_product_int)
       
   610   apply (erule zero_less_mult_pos)
       
   611   apply arith
       
   612   done
       
   613 
       
   614 lemma dvd_prime_factors_nat [intro]:
       
   615   fixes x y :: nat
       
   616   shows "0 < y \<Longrightarrow> x dvd y \<Longrightarrow> prime_factors x \<le> prime_factors y"
       
   617   apply (simp only: prime_factors_altdef_nat)
       
   618   apply auto
       
   619   apply (metis dvd_multiplicity_nat le_0_eq neq0_conv)
       
   620   done
       
   621 
       
   622 lemma dvd_prime_factors_int [intro]:
       
   623   fixes x y :: int
       
   624   shows "0 < y \<Longrightarrow> 0 \<le> x \<Longrightarrow> x dvd y \<Longrightarrow> prime_factors x \<le> prime_factors y"
       
   625   apply (auto simp add: prime_factors_altdef_int)
       
   626   apply (metis dvd_multiplicity_int le_0_eq neq0_conv)
       
   627   done
       
   628 
       
   629 lemma multiplicity_dvd_nat:
       
   630   fixes x y :: nat
       
   631   shows "0 < x \<Longrightarrow> 0 < y \<Longrightarrow> \<forall>p. multiplicity p x \<le> multiplicity p y \<Longrightarrow> x dvd y"
       
   632   apply (subst prime_factorization_nat [of x], assumption)
       
   633   apply (subst prime_factorization_nat [of y], assumption)
       
   634   apply (rule setprod_dvd_setprod_subset2)
       
   635   apply force
       
   636   apply (subst prime_factors_altdef_nat)+
       
   637   apply auto
       
   638   apply (metis gr0I le_0_eq less_not_refl)
       
   639   apply (metis le_imp_power_dvd)
       
   640   done
       
   641 
       
   642 lemma multiplicity_dvd_int:
       
   643   fixes x y :: int
       
   644   shows "0 < x \<Longrightarrow> 0 < y \<Longrightarrow> \<forall>p\<ge>0. multiplicity p x \<le> multiplicity p y \<Longrightarrow> x dvd y"
       
   645   apply (subst prime_factorization_int [of x], assumption)
       
   646   apply (subst prime_factorization_int [of y], assumption)
       
   647   apply (rule setprod_dvd_setprod_subset2)
       
   648   apply force
       
   649   apply (subst prime_factors_altdef_int)+
       
   650   apply auto
       
   651   apply (metis le_imp_power_dvd prime_factors_ge_0_int)
       
   652   done
       
   653 
       
   654 lemma multiplicity_dvd'_nat:
       
   655   fixes x y :: nat
       
   656   assumes "0 < x"
       
   657   assumes "\<forall>p. prime p \<longrightarrow> multiplicity p x \<le> multiplicity p y"
       
   658   shows "x dvd y"
       
   659   using dvd_0_right assms by (metis (no_types) le0 multiplicity_dvd_nat multiplicity_nonprime_nat not_gr0)
       
   660 
       
   661 lemma multiplicity_dvd'_int:
       
   662   fixes x y :: int
       
   663   shows "0 < x \<Longrightarrow> 0 \<le> y \<Longrightarrow>
       
   664     \<forall>p. prime p \<longrightarrow> multiplicity p x \<le> multiplicity p y \<Longrightarrow> x dvd y"
       
   665   by (metis dvd_int_iff abs_of_nat multiplicity_dvd'_nat multiplicity_int_def nat_int
       
   666     zero_le_imp_eq_int zero_less_imp_eq_int)
       
   667 
       
   668 lemma dvd_multiplicity_eq_nat:
       
   669   fixes x y :: nat
       
   670   shows "0 < x \<Longrightarrow> 0 < y \<Longrightarrow> x dvd y \<longleftrightarrow> (\<forall>p. multiplicity p x \<le> multiplicity p y)"
       
   671   by (auto intro: dvd_multiplicity_nat multiplicity_dvd_nat)
       
   672 
       
   673 lemma dvd_multiplicity_eq_int: "0 < (x::int) \<Longrightarrow> 0 < y \<Longrightarrow>
       
   674     (x dvd y) = (\<forall>p\<ge>0. multiplicity p x \<le> multiplicity p y)"
       
   675   by (auto intro: dvd_multiplicity_int multiplicity_dvd_int)
       
   676 
       
   677 lemma prime_factors_altdef2_nat:
       
   678   fixes n :: nat
       
   679   shows "n > 0 \<Longrightarrow> p \<in> prime_factors n \<longleftrightarrow> prime p \<and> p dvd n"
       
   680   apply (cases "prime p")
       
   681   apply auto
       
   682   apply (subst prime_factorization_nat [where n = n], assumption)
       
   683   apply (rule dvd_trans)
       
   684   apply (rule dvd_power [where x = p and n = "multiplicity p n"])
       
   685   apply (subst (asm) prime_factors_altdef_nat, force)
       
   686   apply rule
       
   687   apply auto
       
   688   apply (metis One_nat_def Zero_not_Suc dvd_multiplicity_nat le0
       
   689     le_antisym multiplicity_not_factor_nat multiplicity_prime_nat)
       
   690   done
       
   691 
       
   692 lemma prime_factors_altdef2_int:
       
   693   fixes n :: int
       
   694   assumes "n > 0"
       
   695   shows "p \<in> prime_factors n \<longleftrightarrow> prime p \<and> p dvd n"
       
   696   using assms by (simp add:  prime_factors_altdef2_nat [transferred])
       
   697 
       
   698 lemma multiplicity_eq_nat:
       
   699   fixes x and y::nat
       
   700   assumes [arith]: "x > 0" "y > 0"
       
   701     and mult_eq [simp]: "\<And>p. prime p \<Longrightarrow> multiplicity p x = multiplicity p y"
       
   702   shows "x = y"
       
   703   apply (rule dvd_antisym)
       
   704   apply (auto intro: multiplicity_dvd'_nat)
       
   705   done
       
   706 
       
   707 lemma multiplicity_eq_int:
       
   708   fixes x y :: int
       
   709   assumes [arith]: "x > 0" "y > 0"
       
   710     and mult_eq [simp]: "\<And>p. prime p \<Longrightarrow> multiplicity p x = multiplicity p y"
       
   711   shows "x = y"
       
   712   apply (rule dvd_antisym [transferred])
       
   713   apply (auto intro: multiplicity_dvd'_int)
       
   714   done
       
   715 
       
   716 
       
   717 subsection \<open>An application\<close>
       
   718 
       
   719 lemma gcd_eq_nat:
       
   720   fixes x y :: nat
       
   721   assumes pos [arith]: "x > 0" "y > 0"
       
   722   shows "gcd x y =
       
   723     (\<Prod>p \<in> prime_factors x \<union> prime_factors y. p ^ min (multiplicity p x) (multiplicity p y))"
       
   724   (is "_ = ?z")
       
   725 proof -
       
   726   have [arith]: "?z > 0" 
       
   727     using prime_factors_gt_0_nat by auto
       
   728   have aux: "\<And>p. prime p \<Longrightarrow> multiplicity p ?z = min (multiplicity p x) (multiplicity p y)"
       
   729     apply (subst multiplicity_prod_prime_powers_nat)
       
   730     apply auto
       
   731     done
       
   732   have "?z dvd x"
       
   733     by (intro multiplicity_dvd'_nat) (auto simp add: aux intro: prime_gt_0_nat)
       
   734   moreover have "?z dvd y"
       
   735     by (intro multiplicity_dvd'_nat) (auto simp add: aux intro: prime_gt_0_nat)
       
   736   moreover have "w dvd x \<and> w dvd y \<longrightarrow> w dvd ?z" for w
       
   737   proof (cases "w = 0")
       
   738     case True
       
   739     then show ?thesis by simp
       
   740   next
       
   741     case False
       
   742     then show ?thesis
       
   743       apply auto
       
   744       apply (erule multiplicity_dvd'_nat)
       
   745       apply (auto intro: dvd_multiplicity_nat simp add: aux)
       
   746       done
       
   747   qed
       
   748   ultimately have "?z = gcd x y"
       
   749     by (subst gcd_unique_nat [symmetric], blast)
       
   750   then show ?thesis
       
   751     by auto
       
   752 qed
       
   753 
       
   754 lemma lcm_eq_nat:
       
   755   assumes pos [arith]: "x > 0" "y > 0"
       
   756   shows "lcm (x::nat) y =
       
   757     (\<Prod>p \<in> prime_factors x \<union> prime_factors y. p ^ max (multiplicity p x) (multiplicity p y))"
       
   758   (is "_ = ?z")
       
   759 proof -
       
   760   have [arith]: "?z > 0"
       
   761     by (auto intro: prime_gt_0_nat)
       
   762   have aux: "\<And>p. prime p \<Longrightarrow> multiplicity p ?z = max (multiplicity p x) (multiplicity p y)"
       
   763     apply (subst multiplicity_prod_prime_powers_nat)
       
   764     apply auto
       
   765     done
       
   766   have "x dvd ?z"
       
   767     by (intro multiplicity_dvd'_nat) (auto simp add: aux)
       
   768   moreover have "y dvd ?z"
       
   769     by (intro multiplicity_dvd'_nat) (auto simp add: aux)
       
   770   moreover have "x dvd w \<and> y dvd w \<longrightarrow> ?z dvd w" for w
       
   771   proof (cases "w = 0")
       
   772     case True
       
   773     then show ?thesis by auto
       
   774   next
       
   775     case False
       
   776     then show ?thesis
       
   777       apply auto
       
   778       apply (rule multiplicity_dvd'_nat)
       
   779       apply (auto intro: prime_gt_0_nat dvd_multiplicity_nat simp add: aux)
       
   780       done
       
   781   qed
       
   782   ultimately have "?z = lcm x y"
       
   783     by (subst lcm_unique_nat [symmetric], blast)
       
   784   then show ?thesis
       
   785     by auto
       
   786 qed
       
   787 
       
   788 lemma multiplicity_gcd_nat:
       
   789   fixes p x y :: nat
       
   790   assumes [arith]: "x > 0" "y > 0"
       
   791   shows "multiplicity p (gcd x y) = min (multiplicity p x) (multiplicity p y)"
       
   792   apply (subst gcd_eq_nat)
       
   793   apply auto
       
   794   apply (subst multiplicity_prod_prime_powers_nat)
       
   795   apply auto
       
   796   done
       
   797 
       
   798 lemma multiplicity_lcm_nat:
       
   799   fixes p x y :: nat
       
   800   assumes [arith]: "x > 0" "y > 0"
       
   801   shows "multiplicity p (lcm x y) = max (multiplicity p x) (multiplicity p y)"
       
   802   apply (subst lcm_eq_nat)
       
   803   apply auto
       
   804   apply (subst multiplicity_prod_prime_powers_nat)
       
   805   apply auto
       
   806   done
       
   807 
       
   808 lemma gcd_lcm_distrib_nat:
       
   809   fixes x y z :: nat
       
   810   shows "gcd x (lcm y z) = lcm (gcd x y) (gcd x z)"
       
   811   apply (cases "x = 0 | y = 0 | z = 0")
       
   812   apply auto
       
   813   apply (rule multiplicity_eq_nat)
       
   814   apply (auto simp add: multiplicity_gcd_nat multiplicity_lcm_nat lcm_pos_nat)
       
   815   done
       
   816 
       
   817 lemma gcd_lcm_distrib_int:
       
   818   fixes x y z :: int
       
   819   shows "gcd x (lcm y z) = lcm (gcd x y) (gcd x z)"
       
   820   apply (subst (1 2 3) gcd_abs_int)
       
   821   apply (subst lcm_abs_int)
       
   822   apply (subst (2) abs_of_nonneg)
       
   823   apply force
       
   824   apply (rule gcd_lcm_distrib_nat [transferred])
       
   825   apply auto
       
   826   done
       
   827 
       
   828 end