src/HOL/Number_Theory/UniqueFactorization.thy
changeset 32479 521cc9bf2958
parent 31952 40501bb2d57c
child 33657 a4179bf442d1
equal deleted inserted replaced
32478:87201c60ae7d 32479:521cc9bf2958
       
     1 (*  Title:      UniqueFactorization.thy
       
     2     ID:         
       
     3     Author:     Jeremy Avigad
       
     4 
       
     5     
       
     6     Unique factorization for the natural numbers and the integers.
       
     7 
       
     8     Note: there were previous Isabelle formalizations of unique
       
     9     factorization due to Thomas Marthedal Rasmussen, and, building on
       
    10     that, by Jeremy Avigad and David Gray.  
       
    11 *)
       
    12 
       
    13 header {* UniqueFactorization *}
       
    14 
       
    15 theory UniqueFactorization
       
    16 imports Cong Multiset
       
    17 begin
       
    18 
       
    19 (* inherited from Multiset *)
       
    20 declare One_nat_def [simp del] 
       
    21 
       
    22 (* As a simp or intro rule,
       
    23 
       
    24      prime p \<Longrightarrow> p > 0
       
    25 
       
    26    wreaks havoc here. When the premise includes ALL x :# M. prime x, it 
       
    27    leads to the backchaining
       
    28 
       
    29      x > 0  
       
    30      prime x 
       
    31      x :# M   which is, unfortunately,
       
    32      count M x > 0
       
    33 *)
       
    34 
       
    35 
       
    36 (* useful facts *)
       
    37 
       
    38 lemma setsum_Un2: "finite (A Un B) \<Longrightarrow> 
       
    39     setsum f (A Un B) = setsum f (A - B) + setsum f (B - A) + 
       
    40       setsum f (A Int B)"
       
    41   apply (subgoal_tac "A Un B = (A - B) Un (B - A) Un (A Int B)")
       
    42   apply (erule ssubst)
       
    43   apply (subst setsum_Un_disjoint)
       
    44   apply auto
       
    45   apply (subst setsum_Un_disjoint)
       
    46   apply auto
       
    47 done
       
    48 
       
    49 lemma setprod_Un2: "finite (A Un B) \<Longrightarrow> 
       
    50     setprod f (A Un B) = setprod f (A - B) * setprod f (B - A) * 
       
    51       setprod f (A Int B)"
       
    52   apply (subgoal_tac "A Un B = (A - B) Un (B - A) Un (A Int B)")
       
    53   apply (erule ssubst)
       
    54   apply (subst setprod_Un_disjoint)
       
    55   apply auto
       
    56   apply (subst setprod_Un_disjoint)
       
    57   apply auto
       
    58 done
       
    59  
       
    60 (* Should this go in Multiset.thy? *)
       
    61 (* TN: No longer an intro-rule; needed only once and might get in the way *)
       
    62 lemma multiset_eqI: "[| !!x. count M x = count N x |] ==> M = N"
       
    63   by (subst multiset_eq_conv_count_eq, blast)
       
    64 
       
    65 (* Here is a version of set product for multisets. Is it worth moving
       
    66    to multiset.thy? If so, one should similarly define msetsum for abelian 
       
    67    semirings, using of_nat. Also, is it worth developing bounded quantifiers 
       
    68    "ALL i :# M. P i"? 
       
    69 *)
       
    70 
       
    71 constdefs
       
    72   msetprod :: "('a => ('b::{power,comm_monoid_mult})) => 'a multiset => 'b"
       
    73   "msetprod f M == setprod (%x. (f x)^(count M x)) (set_of M)"
       
    74 
       
    75 syntax
       
    76   "_msetprod" :: "pttrn => 'a set => 'b => 'b::comm_monoid_mult" 
       
    77       ("(3PROD _:#_. _)" [0, 51, 10] 10)
       
    78 
       
    79 translations
       
    80   "PROD i :# A. b" == "msetprod (%i. b) A"
       
    81 
       
    82 lemma msetprod_Un: "msetprod f (A+B) = msetprod f A * msetprod f B" 
       
    83   apply (simp add: msetprod_def power_add)
       
    84   apply (subst setprod_Un2)
       
    85   apply auto
       
    86   apply (subgoal_tac 
       
    87       "(PROD x:set_of A - set_of B. f x ^ count A x * f x ^ count B x) =
       
    88        (PROD x:set_of A - set_of B. f x ^ count A x)")
       
    89   apply (erule ssubst)
       
    90   apply (subgoal_tac 
       
    91       "(PROD x:set_of B - set_of A. f x ^ count A x * f x ^ count B x) =
       
    92        (PROD x:set_of B - set_of A. f x ^ count B x)")
       
    93   apply (erule ssubst)
       
    94   apply (subgoal_tac "(PROD x:set_of A. f x ^ count A x) = 
       
    95     (PROD x:set_of A - set_of B. f x ^ count A x) *
       
    96     (PROD x:set_of A Int set_of B. f x ^ count A x)")
       
    97   apply (erule ssubst)
       
    98   apply (subgoal_tac "(PROD x:set_of B. f x ^ count B x) = 
       
    99     (PROD x:set_of B - set_of A. f x ^ count B x) *
       
   100     (PROD x:set_of A Int set_of B. f x ^ count B x)")
       
   101   apply (erule ssubst)
       
   102   apply (subst setprod_timesf)
       
   103   apply (force simp add: mult_ac)
       
   104   apply (subst setprod_Un_disjoint [symmetric])
       
   105   apply (auto intro: setprod_cong)
       
   106   apply (subst setprod_Un_disjoint [symmetric])
       
   107   apply (auto intro: setprod_cong)
       
   108 done
       
   109 
       
   110 
       
   111 subsection {* unique factorization: multiset version *}
       
   112 
       
   113 lemma multiset_prime_factorization_exists [rule_format]: "n > 0 --> 
       
   114     (EX M. (ALL (p::nat) : set_of M. prime p) & n = (PROD i :# M. i))"
       
   115 proof (rule nat_less_induct, clarify)
       
   116   fix n :: nat
       
   117   assume ih: "ALL m < n. 0 < m --> (EX M. (ALL p : set_of M. prime p) & m = 
       
   118       (PROD i :# M. i))"
       
   119   assume "(n::nat) > 0"
       
   120   then have "n = 1 | (n > 1 & prime n) | (n > 1 & ~ prime n)"
       
   121     by arith
       
   122   moreover 
       
   123   {
       
   124     assume "n = 1"
       
   125     then have "(ALL p : set_of {#}. prime p) & n = (PROD i :# {#}. i)"
       
   126         by (auto simp add: msetprod_def)
       
   127   } 
       
   128   moreover 
       
   129   {
       
   130     assume "n > 1" and "prime n"
       
   131     then have "(ALL p : set_of {# n #}. prime p) & n = (PROD i :# {# n #}. i)"
       
   132       by (auto simp add: msetprod_def)
       
   133   } 
       
   134   moreover 
       
   135   {
       
   136     assume "n > 1" and "~ prime n"
       
   137     from prems not_prime_eq_prod_nat
       
   138       obtain m k where "n = m * k & 1 < m & m < n & 1 < k & k < n"
       
   139         by blast
       
   140     with ih obtain Q R where "(ALL p : set_of Q. prime p) & m = (PROD i:#Q. i)"
       
   141         and "(ALL p: set_of R. prime p) & k = (PROD i:#R. i)"
       
   142       by blast
       
   143     hence "(ALL p: set_of (Q + R). prime p) & n = (PROD i :# Q + R. i)"
       
   144       by (auto simp add: prems msetprod_Un set_of_union)
       
   145     then have "EX M. (ALL p : set_of M. prime p) & n = (PROD i :# M. i)"..
       
   146   }
       
   147   ultimately show "EX M. (ALL p : set_of M. prime p) & n = (PROD i::nat:#M. i)"
       
   148     by blast
       
   149 qed
       
   150 
       
   151 lemma multiset_prime_factorization_unique_aux:
       
   152   fixes a :: nat
       
   153   assumes "(ALL p : set_of M. prime p)" and
       
   154     "(ALL p : set_of N. prime p)" and
       
   155     "(PROD i :# M. i) dvd (PROD i:# N. i)"
       
   156   shows
       
   157     "count M a <= count N a"
       
   158 proof cases
       
   159   assume "a : set_of M"
       
   160   with prems have a: "prime a"
       
   161     by auto
       
   162   with prems have "a ^ count M a dvd (PROD i :# M. i)"
       
   163     by (auto intro: dvd_setprod simp add: msetprod_def)
       
   164   also have "... dvd (PROD i :# N. i)"
       
   165     by (rule prems)
       
   166   also have "... = (PROD i : (set_of N). i ^ (count N i))"
       
   167     by (simp add: msetprod_def)
       
   168   also have "... = 
       
   169       a^(count N a) * (PROD i : (set_of N - {a}). i ^ (count N i))"
       
   170     proof (cases)
       
   171       assume "a : set_of N"
       
   172       hence b: "set_of N = {a} Un (set_of N - {a})"
       
   173         by auto
       
   174       thus ?thesis
       
   175         by (subst (1) b, subst setprod_Un_disjoint, auto)
       
   176     next
       
   177       assume "a ~: set_of N" 
       
   178       thus ?thesis
       
   179         by auto
       
   180     qed
       
   181   finally have "a ^ count M a dvd 
       
   182       a^(count N a) * (PROD i : (set_of N - {a}). i ^ (count N i))".
       
   183   moreover have "coprime (a ^ count M a)
       
   184       (PROD i : (set_of N - {a}). i ^ (count N i))"
       
   185     apply (subst gcd_commute_nat)
       
   186     apply (rule setprod_coprime_nat)
       
   187     apply (rule primes_imp_powers_coprime_nat)
       
   188     apply (insert prems, auto) 
       
   189     done
       
   190   ultimately have "a ^ count M a dvd a^(count N a)"
       
   191     by (elim coprime_dvd_mult_nat)
       
   192   with a show ?thesis 
       
   193     by (intro power_dvd_imp_le, auto)
       
   194 next
       
   195   assume "a ~: set_of M"
       
   196   thus ?thesis by auto
       
   197 qed
       
   198 
       
   199 lemma multiset_prime_factorization_unique:
       
   200   assumes "(ALL (p::nat) : set_of M. prime p)" and
       
   201     "(ALL p : set_of N. prime p)" and
       
   202     "(PROD i :# M. i) = (PROD i:# N. i)"
       
   203   shows
       
   204     "M = N"
       
   205 proof -
       
   206   {
       
   207     fix a
       
   208     from prems have "count M a <= count N a"
       
   209       by (intro multiset_prime_factorization_unique_aux, auto) 
       
   210     moreover from prems have "count N a <= count M a"
       
   211       by (intro multiset_prime_factorization_unique_aux, auto) 
       
   212     ultimately have "count M a = count N a"
       
   213       by auto
       
   214   }
       
   215   thus ?thesis by (simp add:multiset_eq_conv_count_eq)
       
   216 qed
       
   217 
       
   218 constdefs
       
   219   multiset_prime_factorization :: "nat => nat multiset"
       
   220   "multiset_prime_factorization n ==
       
   221      if n > 0 then (THE M. ((ALL p : set_of M. prime p) & 
       
   222        n = (PROD i :# M. i)))
       
   223      else {#}"
       
   224 
       
   225 lemma multiset_prime_factorization: "n > 0 ==>
       
   226     (ALL p : set_of (multiset_prime_factorization n). prime p) &
       
   227        n = (PROD i :# (multiset_prime_factorization n). i)"
       
   228   apply (unfold multiset_prime_factorization_def)
       
   229   apply clarsimp
       
   230   apply (frule multiset_prime_factorization_exists)
       
   231   apply clarify
       
   232   apply (rule theI)
       
   233   apply (insert multiset_prime_factorization_unique, blast)+
       
   234 done
       
   235 
       
   236 
       
   237 subsection {* Prime factors and multiplicity for nats and ints *}
       
   238 
       
   239 class unique_factorization =
       
   240 
       
   241 fixes
       
   242   multiplicity :: "'a \<Rightarrow> 'a \<Rightarrow> nat" and
       
   243   prime_factors :: "'a \<Rightarrow> 'a set"
       
   244 
       
   245 (* definitions for the natural numbers *)
       
   246 
       
   247 instantiation nat :: unique_factorization
       
   248 
       
   249 begin
       
   250 
       
   251 definition
       
   252   multiplicity_nat :: "nat \<Rightarrow> nat \<Rightarrow> nat"
       
   253 where
       
   254   "multiplicity_nat p n = count (multiset_prime_factorization n) p"
       
   255 
       
   256 definition
       
   257   prime_factors_nat :: "nat \<Rightarrow> nat set"
       
   258 where
       
   259   "prime_factors_nat n = set_of (multiset_prime_factorization n)"
       
   260 
       
   261 instance proof qed
       
   262 
       
   263 end
       
   264 
       
   265 (* definitions for the integers *)
       
   266 
       
   267 instantiation int :: unique_factorization
       
   268 
       
   269 begin
       
   270 
       
   271 definition
       
   272   multiplicity_int :: "int \<Rightarrow> int \<Rightarrow> nat"
       
   273 where
       
   274   "multiplicity_int p n = multiplicity (nat p) (nat n)"
       
   275 
       
   276 definition
       
   277   prime_factors_int :: "int \<Rightarrow> int set"
       
   278 where
       
   279   "prime_factors_int n = int ` (prime_factors (nat n))"
       
   280 
       
   281 instance proof qed
       
   282 
       
   283 end
       
   284 
       
   285 
       
   286 subsection {* Set up transfer *}
       
   287 
       
   288 lemma transfer_nat_int_prime_factors: 
       
   289   "prime_factors (nat n) = nat ` prime_factors n"
       
   290   unfolding prime_factors_int_def apply auto
       
   291   by (subst transfer_int_nat_set_return_embed, assumption)
       
   292 
       
   293 lemma transfer_nat_int_prime_factors_closure: "n >= 0 \<Longrightarrow> 
       
   294     nat_set (prime_factors n)"
       
   295   by (auto simp add: nat_set_def prime_factors_int_def)
       
   296 
       
   297 lemma transfer_nat_int_multiplicity: "p >= 0 \<Longrightarrow> n >= 0 \<Longrightarrow>
       
   298   multiplicity (nat p) (nat n) = multiplicity p n"
       
   299   by (auto simp add: multiplicity_int_def)
       
   300 
       
   301 declare TransferMorphism_nat_int[transfer add return: 
       
   302   transfer_nat_int_prime_factors transfer_nat_int_prime_factors_closure
       
   303   transfer_nat_int_multiplicity]
       
   304 
       
   305 
       
   306 lemma transfer_int_nat_prime_factors:
       
   307     "prime_factors (int n) = int ` prime_factors n"
       
   308   unfolding prime_factors_int_def by auto
       
   309 
       
   310 lemma transfer_int_nat_prime_factors_closure: "is_nat n \<Longrightarrow> 
       
   311     nat_set (prime_factors n)"
       
   312   by (simp only: transfer_nat_int_prime_factors_closure is_nat_def)
       
   313 
       
   314 lemma transfer_int_nat_multiplicity: 
       
   315     "multiplicity (int p) (int n) = multiplicity p n"
       
   316   by (auto simp add: multiplicity_int_def)
       
   317 
       
   318 declare TransferMorphism_int_nat[transfer add return: 
       
   319   transfer_int_nat_prime_factors transfer_int_nat_prime_factors_closure
       
   320   transfer_int_nat_multiplicity]
       
   321 
       
   322 
       
   323 subsection {* Properties of prime factors and multiplicity for nats and ints *}
       
   324 
       
   325 lemma prime_factors_ge_0_int [elim]: "p : prime_factors (n::int) \<Longrightarrow> p >= 0"
       
   326   by (unfold prime_factors_int_def, auto)
       
   327 
       
   328 lemma prime_factors_prime_nat [intro]: "p : prime_factors (n::nat) \<Longrightarrow> prime p"
       
   329   apply (case_tac "n = 0")
       
   330   apply (simp add: prime_factors_nat_def multiset_prime_factorization_def)
       
   331   apply (auto simp add: prime_factors_nat_def multiset_prime_factorization)
       
   332 done
       
   333 
       
   334 lemma prime_factors_prime_int [intro]:
       
   335   assumes "n >= 0" and "p : prime_factors (n::int)"
       
   336   shows "prime p"
       
   337 
       
   338   apply (rule prime_factors_prime_nat [transferred, of n p])
       
   339   using prems apply auto
       
   340 done
       
   341 
       
   342 lemma prime_factors_gt_0_nat [elim]: "p : prime_factors x \<Longrightarrow> p > (0::nat)"
       
   343   by (frule prime_factors_prime_nat, auto)
       
   344 
       
   345 lemma prime_factors_gt_0_int [elim]: "x >= 0 \<Longrightarrow> p : prime_factors x \<Longrightarrow> 
       
   346     p > (0::int)"
       
   347   by (frule (1) prime_factors_prime_int, auto)
       
   348 
       
   349 lemma prime_factors_finite_nat [iff]: "finite (prime_factors (n::nat))"
       
   350   by (unfold prime_factors_nat_def, auto)
       
   351 
       
   352 lemma prime_factors_finite_int [iff]: "finite (prime_factors (n::int))"
       
   353   by (unfold prime_factors_int_def, auto)
       
   354 
       
   355 lemma prime_factors_altdef_nat: "prime_factors (n::nat) = 
       
   356     {p. multiplicity p n > 0}"
       
   357   by (force simp add: prime_factors_nat_def multiplicity_nat_def)
       
   358 
       
   359 lemma prime_factors_altdef_int: "prime_factors (n::int) = 
       
   360     {p. p >= 0 & multiplicity p n > 0}"
       
   361   apply (unfold prime_factors_int_def multiplicity_int_def)
       
   362   apply (subst prime_factors_altdef_nat)
       
   363   apply (auto simp add: image_def)
       
   364 done
       
   365 
       
   366 lemma prime_factorization_nat: "(n::nat) > 0 \<Longrightarrow> 
       
   367     n = (PROD p : prime_factors n. p^(multiplicity p n))"
       
   368   by (frule multiset_prime_factorization, 
       
   369     simp add: prime_factors_nat_def multiplicity_nat_def msetprod_def)
       
   370 
       
   371 thm prime_factorization_nat [transferred] 
       
   372 
       
   373 lemma prime_factorization_int: 
       
   374   assumes "(n::int) > 0"
       
   375   shows "n = (PROD p : prime_factors n. p^(multiplicity p n))"
       
   376 
       
   377   apply (rule prime_factorization_nat [transferred, of n])
       
   378   using prems apply auto
       
   379 done
       
   380 
       
   381 lemma neq_zero_eq_gt_zero_nat: "((x::nat) ~= 0) = (x > 0)"
       
   382   by auto
       
   383 
       
   384 lemma prime_factorization_unique_nat: 
       
   385     "S = { (p::nat) . f p > 0} \<Longrightarrow> finite S \<Longrightarrow> (ALL p : S. prime p) \<Longrightarrow>
       
   386       n = (PROD p : S. p^(f p)) \<Longrightarrow>
       
   387         S = prime_factors n & (ALL p. f p = multiplicity p n)"
       
   388   apply (subgoal_tac "multiset_prime_factorization n = Abs_multiset
       
   389       f")
       
   390   apply (unfold prime_factors_nat_def multiplicity_nat_def)
       
   391   apply (simp add: set_of_def count_def Abs_multiset_inverse multiset_def)
       
   392   apply (unfold multiset_prime_factorization_def)
       
   393   apply (subgoal_tac "n > 0")
       
   394   prefer 2
       
   395   apply force
       
   396   apply (subst if_P, assumption)
       
   397   apply (rule the1_equality)
       
   398   apply (rule ex_ex1I)
       
   399   apply (rule multiset_prime_factorization_exists, assumption)
       
   400   apply (rule multiset_prime_factorization_unique)
       
   401   apply force
       
   402   apply force
       
   403   apply force
       
   404   unfolding set_of_def count_def msetprod_def
       
   405   apply (subgoal_tac "f : multiset")
       
   406   apply (auto simp only: Abs_multiset_inverse)
       
   407   unfolding multiset_def apply force 
       
   408 done
       
   409 
       
   410 lemma prime_factors_characterization_nat: "S = {p. 0 < f (p::nat)} \<Longrightarrow> 
       
   411     finite S \<Longrightarrow> (ALL p:S. prime p) \<Longrightarrow> n = (PROD p:S. p ^ f p) \<Longrightarrow>
       
   412       prime_factors n = S"
       
   413   by (rule prime_factorization_unique_nat [THEN conjunct1, symmetric],
       
   414     assumption+)
       
   415 
       
   416 lemma prime_factors_characterization'_nat: 
       
   417   "finite {p. 0 < f (p::nat)} \<Longrightarrow>
       
   418     (ALL p. 0 < f p \<longrightarrow> prime p) \<Longrightarrow>
       
   419       prime_factors (PROD p | 0 < f p . p ^ f p) = {p. 0 < f p}"
       
   420   apply (rule prime_factors_characterization_nat)
       
   421   apply auto
       
   422 done
       
   423 
       
   424 (* A minor glitch:*)
       
   425 
       
   426 thm prime_factors_characterization'_nat 
       
   427     [where f = "%x. f (int (x::nat))", 
       
   428       transferred direction: nat "op <= (0::int)", rule_format]
       
   429 
       
   430 (*
       
   431   Transfer isn't smart enough to know that the "0 < f p" should 
       
   432   remain a comparison between nats. But the transfer still works. 
       
   433 *)
       
   434 
       
   435 lemma primes_characterization'_int [rule_format]: 
       
   436     "finite {p. p >= 0 & 0 < f (p::int)} \<Longrightarrow>
       
   437       (ALL p. 0 < f p \<longrightarrow> prime p) \<Longrightarrow>
       
   438         prime_factors (PROD p | p >=0 & 0 < f p . p ^ f p) = 
       
   439           {p. p >= 0 & 0 < f p}"
       
   440 
       
   441   apply (insert prime_factors_characterization'_nat 
       
   442     [where f = "%x. f (int (x::nat))", 
       
   443     transferred direction: nat "op <= (0::int)"])
       
   444   apply auto
       
   445 done
       
   446 
       
   447 lemma prime_factors_characterization_int: "S = {p. 0 < f (p::int)} \<Longrightarrow> 
       
   448     finite S \<Longrightarrow> (ALL p:S. prime p) \<Longrightarrow> n = (PROD p:S. p ^ f p) \<Longrightarrow>
       
   449       prime_factors n = S"
       
   450   apply simp
       
   451   apply (subgoal_tac "{p. 0 < f p} = {p. 0 <= p & 0 < f p}")
       
   452   apply (simp only:)
       
   453   apply (subst primes_characterization'_int)
       
   454   apply auto
       
   455   apply (auto simp add: prime_ge_0_int)
       
   456 done
       
   457 
       
   458 lemma multiplicity_characterization_nat: "S = {p. 0 < f (p::nat)} \<Longrightarrow> 
       
   459     finite S \<Longrightarrow> (ALL p:S. prime p) \<Longrightarrow> n = (PROD p:S. p ^ f p) \<Longrightarrow>
       
   460       multiplicity p n = f p"
       
   461   by (frule prime_factorization_unique_nat [THEN conjunct2, rule_format, 
       
   462     symmetric], auto)
       
   463 
       
   464 lemma multiplicity_characterization'_nat: "finite {p. 0 < f (p::nat)} \<longrightarrow>
       
   465     (ALL p. 0 < f p \<longrightarrow> prime p) \<longrightarrow>
       
   466       multiplicity p (PROD p | 0 < f p . p ^ f p) = f p"
       
   467   apply (rule impI)+
       
   468   apply (rule multiplicity_characterization_nat)
       
   469   apply auto
       
   470 done
       
   471 
       
   472 lemma multiplicity_characterization'_int [rule_format]: 
       
   473   "finite {p. p >= 0 & 0 < f (p::int)} \<Longrightarrow>
       
   474     (ALL p. 0 < f p \<longrightarrow> prime p) \<Longrightarrow> p >= 0 \<Longrightarrow>
       
   475       multiplicity p (PROD p | p >= 0 & 0 < f p . p ^ f p) = f p"
       
   476 
       
   477   apply (insert multiplicity_characterization'_nat 
       
   478     [where f = "%x. f (int (x::nat))", 
       
   479       transferred direction: nat "op <= (0::int)", rule_format])
       
   480   apply auto
       
   481 done
       
   482 
       
   483 lemma multiplicity_characterization_int: "S = {p. 0 < f (p::int)} \<Longrightarrow> 
       
   484     finite S \<Longrightarrow> (ALL p:S. prime p) \<Longrightarrow> n = (PROD p:S. p ^ f p) \<Longrightarrow>
       
   485       p >= 0 \<Longrightarrow> multiplicity p n = f p"
       
   486   apply simp
       
   487   apply (subgoal_tac "{p. 0 < f p} = {p. 0 <= p & 0 < f p}")
       
   488   apply (simp only:)
       
   489   apply (subst multiplicity_characterization'_int)
       
   490   apply auto
       
   491   apply (auto simp add: prime_ge_0_int)
       
   492 done
       
   493 
       
   494 lemma multiplicity_zero_nat [simp]: "multiplicity (p::nat) 0 = 0"
       
   495   by (simp add: multiplicity_nat_def multiset_prime_factorization_def)
       
   496 
       
   497 lemma multiplicity_zero_int [simp]: "multiplicity (p::int) 0 = 0"
       
   498   by (simp add: multiplicity_int_def) 
       
   499 
       
   500 lemma multiplicity_one_nat [simp]: "multiplicity p (1::nat) = 0"
       
   501   by (subst multiplicity_characterization_nat [where f = "%x. 0"], auto)
       
   502 
       
   503 lemma multiplicity_one_int [simp]: "multiplicity p (1::int) = 0"
       
   504   by (simp add: multiplicity_int_def)
       
   505 
       
   506 lemma multiplicity_prime_nat [simp]: "prime (p::nat) \<Longrightarrow> multiplicity p p = 1"
       
   507   apply (subst multiplicity_characterization_nat
       
   508       [where f = "(%q. if q = p then 1 else 0)"])
       
   509   apply auto
       
   510   apply (case_tac "x = p")
       
   511   apply auto
       
   512 done
       
   513 
       
   514 lemma multiplicity_prime_int [simp]: "prime (p::int) \<Longrightarrow> multiplicity p p = 1"
       
   515   unfolding prime_int_def multiplicity_int_def by auto
       
   516 
       
   517 lemma multiplicity_prime_power_nat [simp]: "prime (p::nat) \<Longrightarrow> 
       
   518     multiplicity p (p^n) = n"
       
   519   apply (case_tac "n = 0")
       
   520   apply auto
       
   521   apply (subst multiplicity_characterization_nat
       
   522       [where f = "(%q. if q = p then n else 0)"])
       
   523   apply auto
       
   524   apply (case_tac "x = p")
       
   525   apply auto
       
   526 done
       
   527 
       
   528 lemma multiplicity_prime_power_int [simp]: "prime (p::int) \<Longrightarrow> 
       
   529     multiplicity p (p^n) = n"
       
   530   apply (frule prime_ge_0_int)
       
   531   apply (auto simp add: prime_int_def multiplicity_int_def nat_power_eq)
       
   532 done
       
   533 
       
   534 lemma multiplicity_nonprime_nat [simp]: "~ prime (p::nat) \<Longrightarrow> 
       
   535     multiplicity p n = 0"
       
   536   apply (case_tac "n = 0")
       
   537   apply auto
       
   538   apply (frule multiset_prime_factorization)
       
   539   apply (auto simp add: set_of_def multiplicity_nat_def)
       
   540 done
       
   541 
       
   542 lemma multiplicity_nonprime_int [simp]: "~ prime (p::int) \<Longrightarrow> multiplicity p n = 0"
       
   543   by (unfold multiplicity_int_def prime_int_def, auto)
       
   544 
       
   545 lemma multiplicity_not_factor_nat [simp]: 
       
   546     "p ~: prime_factors (n::nat) \<Longrightarrow> multiplicity p n = 0"
       
   547   by (subst (asm) prime_factors_altdef_nat, auto)
       
   548 
       
   549 lemma multiplicity_not_factor_int [simp]: 
       
   550     "p >= 0 \<Longrightarrow> p ~: prime_factors (n::int) \<Longrightarrow> multiplicity p n = 0"
       
   551   by (subst (asm) prime_factors_altdef_int, auto)
       
   552 
       
   553 lemma multiplicity_product_aux_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow>
       
   554     (prime_factors k) Un (prime_factors l) = prime_factors (k * l) &
       
   555     (ALL p. multiplicity p k + multiplicity p l = multiplicity p (k * l))"
       
   556   apply (rule prime_factorization_unique_nat)
       
   557   apply (simp only: prime_factors_altdef_nat)
       
   558   apply auto
       
   559   apply (subst power_add)
       
   560   apply (subst setprod_timesf)
       
   561   apply (rule arg_cong2)back back
       
   562   apply (subgoal_tac "prime_factors k Un prime_factors l = prime_factors k Un 
       
   563       (prime_factors l - prime_factors k)")
       
   564   apply (erule ssubst)
       
   565   apply (subst setprod_Un_disjoint)
       
   566   apply auto
       
   567   apply (subgoal_tac "(\<Prod>p\<in>prime_factors l - prime_factors k. p ^ multiplicity p k) = 
       
   568       (\<Prod>p\<in>prime_factors l - prime_factors k. 1)")
       
   569   apply (erule ssubst)
       
   570   apply (simp add: setprod_1)
       
   571   apply (erule prime_factorization_nat)
       
   572   apply (rule setprod_cong, auto)
       
   573   apply (subgoal_tac "prime_factors k Un prime_factors l = prime_factors l Un 
       
   574       (prime_factors k - prime_factors l)")
       
   575   apply (erule ssubst)
       
   576   apply (subst setprod_Un_disjoint)
       
   577   apply auto
       
   578   apply (subgoal_tac "(\<Prod>p\<in>prime_factors k - prime_factors l. p ^ multiplicity p l) = 
       
   579       (\<Prod>p\<in>prime_factors k - prime_factors l. 1)")
       
   580   apply (erule ssubst)
       
   581   apply (simp add: setprod_1)
       
   582   apply (erule prime_factorization_nat)
       
   583   apply (rule setprod_cong, auto)
       
   584 done
       
   585 
       
   586 (* transfer doesn't have the same problem here with the right 
       
   587    choice of rules. *)
       
   588 
       
   589 lemma multiplicity_product_aux_int: 
       
   590   assumes "(k::int) > 0" and "l > 0"
       
   591   shows 
       
   592     "(prime_factors k) Un (prime_factors l) = prime_factors (k * l) &
       
   593     (ALL p >= 0. multiplicity p k + multiplicity p l = multiplicity p (k * l))"
       
   594 
       
   595   apply (rule multiplicity_product_aux_nat [transferred, of l k])
       
   596   using prems apply auto
       
   597 done
       
   598 
       
   599 lemma prime_factors_product_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> prime_factors (k * l) = 
       
   600     prime_factors k Un prime_factors l"
       
   601   by (rule multiplicity_product_aux_nat [THEN conjunct1, symmetric])
       
   602 
       
   603 lemma prime_factors_product_int: "(k::int) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> prime_factors (k * l) = 
       
   604     prime_factors k Un prime_factors l"
       
   605   by (rule multiplicity_product_aux_int [THEN conjunct1, symmetric])
       
   606 
       
   607 lemma multiplicity_product_nat: "(k::nat) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> multiplicity p (k * l) = 
       
   608     multiplicity p k + multiplicity p l"
       
   609   by (rule multiplicity_product_aux_nat [THEN conjunct2, rule_format, 
       
   610       symmetric])
       
   611 
       
   612 lemma multiplicity_product_int: "(k::int) > 0 \<Longrightarrow> l > 0 \<Longrightarrow> p >= 0 \<Longrightarrow> 
       
   613     multiplicity p (k * l) = multiplicity p k + multiplicity p l"
       
   614   by (rule multiplicity_product_aux_int [THEN conjunct2, rule_format, 
       
   615       symmetric])
       
   616 
       
   617 lemma multiplicity_setprod_nat: "finite S \<Longrightarrow> (ALL x : S. f x > 0) \<Longrightarrow> 
       
   618     multiplicity (p::nat) (PROD x : S. f x) = 
       
   619       (SUM x : S. multiplicity p (f x))"
       
   620   apply (induct set: finite)
       
   621   apply auto
       
   622   apply (subst multiplicity_product_nat)
       
   623   apply auto
       
   624 done
       
   625 
       
   626 (* Transfer is delicate here for two reasons: first, because there is
       
   627    an implicit quantifier over functions (f), and, second, because the 
       
   628    product over the multiplicity should not be translated to an integer 
       
   629    product.
       
   630 
       
   631    The way to handle the first is to use quantifier rules for functions.
       
   632    The way to handle the second is to turn off the offending rule.
       
   633 *)
       
   634 
       
   635 lemma transfer_nat_int_sum_prod_closure3:
       
   636   "(SUM x : A. int (f x)) >= 0"
       
   637   "(PROD x : A. int (f x)) >= 0"
       
   638   apply (rule setsum_nonneg, auto)
       
   639   apply (rule setprod_nonneg, auto)
       
   640 done
       
   641 
       
   642 declare TransferMorphism_nat_int[transfer 
       
   643   add return: transfer_nat_int_sum_prod_closure3
       
   644   del: transfer_nat_int_sum_prod2 (1)]
       
   645 
       
   646 lemma multiplicity_setprod_int: "p >= 0 \<Longrightarrow> finite S \<Longrightarrow> 
       
   647   (ALL x : S. f x > 0) \<Longrightarrow> 
       
   648     multiplicity (p::int) (PROD x : S. f x) = 
       
   649       (SUM x : S. multiplicity p (f x))"
       
   650 
       
   651   apply (frule multiplicity_setprod_nat
       
   652     [where f = "%x. nat(int(nat(f x)))", 
       
   653       transferred direction: nat "op <= (0::int)"])
       
   654   apply auto
       
   655   apply (subst (asm) setprod_cong)
       
   656   apply (rule refl)
       
   657   apply (rule if_P)
       
   658   apply auto
       
   659   apply (rule setsum_cong)
       
   660   apply auto
       
   661 done
       
   662 
       
   663 declare TransferMorphism_nat_int[transfer 
       
   664   add return: transfer_nat_int_sum_prod2 (1)]
       
   665 
       
   666 lemma multiplicity_prod_prime_powers_nat:
       
   667     "finite S \<Longrightarrow> (ALL p : S. prime (p::nat)) \<Longrightarrow>
       
   668        multiplicity p (PROD p : S. p ^ f p) = (if p : S then f p else 0)"
       
   669   apply (subgoal_tac "(PROD p : S. p ^ f p) = 
       
   670       (PROD p : S. p ^ (%x. if x : S then f x else 0) p)")
       
   671   apply (erule ssubst)
       
   672   apply (subst multiplicity_characterization_nat)
       
   673   prefer 5 apply (rule refl)
       
   674   apply (rule refl)
       
   675   apply auto
       
   676   apply (subst setprod_mono_one_right)
       
   677   apply assumption
       
   678   prefer 3
       
   679   apply (rule setprod_cong)
       
   680   apply (rule refl)
       
   681   apply auto
       
   682 done
       
   683 
       
   684 (* Here the issue with transfer is the implicit quantifier over S *)
       
   685 
       
   686 lemma multiplicity_prod_prime_powers_int:
       
   687     "(p::int) >= 0 \<Longrightarrow> finite S \<Longrightarrow> (ALL p : S. prime p) \<Longrightarrow>
       
   688        multiplicity p (PROD p : S. p ^ f p) = (if p : S then f p else 0)"
       
   689 
       
   690   apply (subgoal_tac "int ` nat ` S = S")
       
   691   apply (frule multiplicity_prod_prime_powers_nat [where f = "%x. f(int x)" 
       
   692     and S = "nat ` S", transferred])
       
   693   apply auto
       
   694   apply (subst prime_int_def [symmetric])
       
   695   apply auto
       
   696   apply (subgoal_tac "xb >= 0")
       
   697   apply force
       
   698   apply (rule prime_ge_0_int)
       
   699   apply force
       
   700   apply (subst transfer_nat_int_set_return_embed)
       
   701   apply (unfold nat_set_def, auto)
       
   702 done
       
   703 
       
   704 lemma multiplicity_distinct_prime_power_nat: "prime (p::nat) \<Longrightarrow> prime q \<Longrightarrow>
       
   705     p ~= q \<Longrightarrow> multiplicity p (q^n) = 0"
       
   706   apply (subgoal_tac "q^n = setprod (%x. x^n) {q}")
       
   707   apply (erule ssubst)
       
   708   apply (subst multiplicity_prod_prime_powers_nat)
       
   709   apply auto
       
   710 done
       
   711 
       
   712 lemma multiplicity_distinct_prime_power_int: "prime (p::int) \<Longrightarrow> prime q \<Longrightarrow>
       
   713     p ~= q \<Longrightarrow> multiplicity p (q^n) = 0"
       
   714   apply (frule prime_ge_0_int [of q])
       
   715   apply (frule multiplicity_distinct_prime_power_nat [transferred leaving: n]) 
       
   716   prefer 4
       
   717   apply assumption
       
   718   apply auto
       
   719 done
       
   720 
       
   721 lemma dvd_multiplicity_nat: 
       
   722     "(0::nat) < y \<Longrightarrow> x dvd y \<Longrightarrow> multiplicity p x <= multiplicity p y"
       
   723   apply (case_tac "x = 0")
       
   724   apply (auto simp add: dvd_def multiplicity_product_nat)
       
   725 done
       
   726 
       
   727 lemma dvd_multiplicity_int: 
       
   728     "(0::int) < y \<Longrightarrow> 0 <= x \<Longrightarrow> x dvd y \<Longrightarrow> p >= 0 \<Longrightarrow> 
       
   729       multiplicity p x <= multiplicity p y"
       
   730   apply (case_tac "x = 0")
       
   731   apply (auto simp add: dvd_def)
       
   732   apply (subgoal_tac "0 < k")
       
   733   apply (auto simp add: multiplicity_product_int)
       
   734   apply (erule zero_less_mult_pos)
       
   735   apply arith
       
   736 done
       
   737 
       
   738 lemma dvd_prime_factors_nat [intro]:
       
   739     "0 < (y::nat) \<Longrightarrow> x dvd y \<Longrightarrow> prime_factors x <= prime_factors y"
       
   740   apply (simp only: prime_factors_altdef_nat)
       
   741   apply auto
       
   742   apply (frule dvd_multiplicity_nat)
       
   743   apply auto
       
   744 (* It is a shame that auto and arith don't get this. *)
       
   745   apply (erule order_less_le_trans)back
       
   746   apply assumption
       
   747 done
       
   748 
       
   749 lemma dvd_prime_factors_int [intro]:
       
   750     "0 < (y::int) \<Longrightarrow> 0 <= x \<Longrightarrow> x dvd y \<Longrightarrow> prime_factors x <= prime_factors y"
       
   751   apply (auto simp add: prime_factors_altdef_int)
       
   752   apply (erule order_less_le_trans)
       
   753   apply (rule dvd_multiplicity_int)
       
   754   apply auto
       
   755 done
       
   756 
       
   757 lemma multiplicity_dvd_nat: "0 < (x::nat) \<Longrightarrow> 0 < y \<Longrightarrow> 
       
   758     ALL p. multiplicity p x <= multiplicity p y \<Longrightarrow>
       
   759       x dvd y"
       
   760   apply (subst prime_factorization_nat [of x], assumption)
       
   761   apply (subst prime_factorization_nat [of y], assumption)
       
   762   apply (rule setprod_dvd_setprod_subset2)
       
   763   apply force
       
   764   apply (subst prime_factors_altdef_nat)+
       
   765   apply auto
       
   766 (* Again, a shame that auto and arith don't get this. *)
       
   767   apply (drule_tac x = xa in spec, auto)
       
   768   apply (rule le_imp_power_dvd)
       
   769   apply blast
       
   770 done
       
   771 
       
   772 lemma multiplicity_dvd_int: "0 < (x::int) \<Longrightarrow> 0 < y \<Longrightarrow> 
       
   773     ALL p >= 0. multiplicity p x <= multiplicity p y \<Longrightarrow>
       
   774       x dvd y"
       
   775   apply (subst prime_factorization_int [of x], assumption)
       
   776   apply (subst prime_factorization_int [of y], assumption)
       
   777   apply (rule setprod_dvd_setprod_subset2)
       
   778   apply force
       
   779   apply (subst prime_factors_altdef_int)+
       
   780   apply auto
       
   781   apply (rule dvd_power_le)
       
   782   apply auto
       
   783   apply (drule_tac x = xa in spec)
       
   784   apply (erule impE)
       
   785   apply auto
       
   786 done
       
   787 
       
   788 lemma multiplicity_dvd'_nat: "(0::nat) < x \<Longrightarrow> 
       
   789     \<forall>p. prime p \<longrightarrow> multiplicity p x \<le> multiplicity p y \<Longrightarrow> x dvd y"
       
   790   apply (cases "y = 0")
       
   791   apply auto
       
   792   apply (rule multiplicity_dvd_nat, auto)
       
   793   apply (case_tac "prime p")
       
   794   apply auto
       
   795 done
       
   796 
       
   797 lemma multiplicity_dvd'_int: "(0::int) < x \<Longrightarrow> 0 <= y \<Longrightarrow>
       
   798     \<forall>p. prime p \<longrightarrow> multiplicity p x \<le> multiplicity p y \<Longrightarrow> x dvd y"
       
   799   apply (cases "y = 0")
       
   800   apply auto
       
   801   apply (rule multiplicity_dvd_int, auto)
       
   802   apply (case_tac "prime p")
       
   803   apply auto
       
   804 done
       
   805 
       
   806 lemma dvd_multiplicity_eq_nat: "0 < (x::nat) \<Longrightarrow> 0 < y \<Longrightarrow>
       
   807     (x dvd y) = (ALL p. multiplicity p x <= multiplicity p y)"
       
   808   by (auto intro: dvd_multiplicity_nat multiplicity_dvd_nat)
       
   809 
       
   810 lemma dvd_multiplicity_eq_int: "0 < (x::int) \<Longrightarrow> 0 < y \<Longrightarrow>
       
   811     (x dvd y) = (ALL p >= 0. multiplicity p x <= multiplicity p y)"
       
   812   by (auto intro: dvd_multiplicity_int multiplicity_dvd_int)
       
   813 
       
   814 lemma prime_factors_altdef2_nat: "(n::nat) > 0 \<Longrightarrow> 
       
   815     (p : prime_factors n) = (prime p & p dvd n)"
       
   816   apply (case_tac "prime p")
       
   817   apply auto
       
   818   apply (subst prime_factorization_nat [where n = n], assumption)
       
   819   apply (rule dvd_trans) 
       
   820   apply (rule dvd_power [where x = p and n = "multiplicity p n"])
       
   821   apply (subst (asm) prime_factors_altdef_nat, force)
       
   822   apply (rule dvd_setprod)
       
   823   apply auto  
       
   824   apply (subst prime_factors_altdef_nat)
       
   825   apply (subst (asm) dvd_multiplicity_eq_nat)
       
   826   apply auto
       
   827   apply (drule spec [where x = p])
       
   828   apply auto
       
   829 done
       
   830 
       
   831 lemma prime_factors_altdef2_int: 
       
   832   assumes "(n::int) > 0" 
       
   833   shows "(p : prime_factors n) = (prime p & p dvd n)"
       
   834 
       
   835   apply (case_tac "p >= 0")
       
   836   apply (rule prime_factors_altdef2_nat [transferred])
       
   837   using prems apply auto
       
   838   apply (auto simp add: prime_ge_0_int prime_factors_ge_0_int)
       
   839 done
       
   840 
       
   841 lemma multiplicity_eq_nat:
       
   842   fixes x and y::nat 
       
   843   assumes [arith]: "x > 0" "y > 0" and
       
   844     mult_eq [simp]: "!!p. prime p \<Longrightarrow> multiplicity p x = multiplicity p y"
       
   845   shows "x = y"
       
   846 
       
   847   apply (rule dvd_anti_sym)
       
   848   apply (auto intro: multiplicity_dvd'_nat) 
       
   849 done
       
   850 
       
   851 lemma multiplicity_eq_int:
       
   852   fixes x and y::int 
       
   853   assumes [arith]: "x > 0" "y > 0" and
       
   854     mult_eq [simp]: "!!p. prime p \<Longrightarrow> multiplicity p x = multiplicity p y"
       
   855   shows "x = y"
       
   856 
       
   857   apply (rule dvd_anti_sym [transferred])
       
   858   apply (auto intro: multiplicity_dvd'_int) 
       
   859 done
       
   860 
       
   861 
       
   862 subsection {* An application *}
       
   863 
       
   864 lemma gcd_eq_nat: 
       
   865   assumes pos [arith]: "x > 0" "y > 0"
       
   866   shows "gcd (x::nat) y = 
       
   867     (PROD p: prime_factors x Un prime_factors y. 
       
   868       p ^ (min (multiplicity p x) (multiplicity p y)))"
       
   869 proof -
       
   870   def z == "(PROD p: prime_factors (x::nat) Un prime_factors y. 
       
   871       p ^ (min (multiplicity p x) (multiplicity p y)))"
       
   872   have [arith]: "z > 0"
       
   873     unfolding z_def by (rule setprod_pos_nat, auto)
       
   874   have aux: "!!p. prime p \<Longrightarrow> multiplicity p z = 
       
   875       min (multiplicity p x) (multiplicity p y)"
       
   876     unfolding z_def
       
   877     apply (subst multiplicity_prod_prime_powers_nat)
       
   878     apply (auto simp add: multiplicity_not_factor_nat)
       
   879     done
       
   880   have "z dvd x" 
       
   881     by (intro multiplicity_dvd'_nat, auto simp add: aux)
       
   882   moreover have "z dvd y" 
       
   883     by (intro multiplicity_dvd'_nat, auto simp add: aux)
       
   884   moreover have "ALL w. w dvd x & w dvd y \<longrightarrow> w dvd z"
       
   885     apply auto
       
   886     apply (case_tac "w = 0", auto)
       
   887     apply (erule multiplicity_dvd'_nat)
       
   888     apply (auto intro: dvd_multiplicity_nat simp add: aux)
       
   889     done
       
   890   ultimately have "z = gcd x y"
       
   891     by (subst gcd_unique_nat [symmetric], blast)
       
   892   thus ?thesis
       
   893     unfolding z_def by auto
       
   894 qed
       
   895 
       
   896 lemma lcm_eq_nat: 
       
   897   assumes pos [arith]: "x > 0" "y > 0"
       
   898   shows "lcm (x::nat) y = 
       
   899     (PROD p: prime_factors x Un prime_factors y. 
       
   900       p ^ (max (multiplicity p x) (multiplicity p y)))"
       
   901 proof -
       
   902   def z == "(PROD p: prime_factors (x::nat) Un prime_factors y. 
       
   903       p ^ (max (multiplicity p x) (multiplicity p y)))"
       
   904   have [arith]: "z > 0"
       
   905     unfolding z_def by (rule setprod_pos_nat, auto)
       
   906   have aux: "!!p. prime p \<Longrightarrow> multiplicity p z = 
       
   907       max (multiplicity p x) (multiplicity p y)"
       
   908     unfolding z_def
       
   909     apply (subst multiplicity_prod_prime_powers_nat)
       
   910     apply (auto simp add: multiplicity_not_factor_nat)
       
   911     done
       
   912   have "x dvd z" 
       
   913     by (intro multiplicity_dvd'_nat, auto simp add: aux)
       
   914   moreover have "y dvd z" 
       
   915     by (intro multiplicity_dvd'_nat, auto simp add: aux)
       
   916   moreover have "ALL w. x dvd w & y dvd w \<longrightarrow> z dvd w"
       
   917     apply auto
       
   918     apply (case_tac "w = 0", auto)
       
   919     apply (rule multiplicity_dvd'_nat)
       
   920     apply (auto intro: dvd_multiplicity_nat simp add: aux)
       
   921     done
       
   922   ultimately have "z = lcm x y"
       
   923     by (subst lcm_unique_nat [symmetric], blast)
       
   924   thus ?thesis
       
   925     unfolding z_def by auto
       
   926 qed
       
   927 
       
   928 lemma multiplicity_gcd_nat: 
       
   929   assumes [arith]: "x > 0" "y > 0"
       
   930   shows "multiplicity (p::nat) (gcd x y) = 
       
   931     min (multiplicity p x) (multiplicity p y)"
       
   932 
       
   933   apply (subst gcd_eq_nat)
       
   934   apply auto
       
   935   apply (subst multiplicity_prod_prime_powers_nat)
       
   936   apply auto
       
   937 done
       
   938 
       
   939 lemma multiplicity_lcm_nat: 
       
   940   assumes [arith]: "x > 0" "y > 0"
       
   941   shows "multiplicity (p::nat) (lcm x y) = 
       
   942     max (multiplicity p x) (multiplicity p y)"
       
   943 
       
   944   apply (subst lcm_eq_nat)
       
   945   apply auto
       
   946   apply (subst multiplicity_prod_prime_powers_nat)
       
   947   apply auto
       
   948 done
       
   949 
       
   950 lemma gcd_lcm_distrib_nat: "gcd (x::nat) (lcm y z) = lcm (gcd x y) (gcd x z)"
       
   951   apply (case_tac "x = 0 | y = 0 | z = 0") 
       
   952   apply auto
       
   953   apply (rule multiplicity_eq_nat)
       
   954   apply (auto simp add: multiplicity_gcd_nat multiplicity_lcm_nat 
       
   955       lcm_pos_nat)
       
   956 done
       
   957 
       
   958 lemma gcd_lcm_distrib_int: "gcd (x::int) (lcm y z) = lcm (gcd x y) (gcd x z)"
       
   959   apply (subst (1 2 3) gcd_abs_int)
       
   960   apply (subst lcm_abs_int)
       
   961   apply (subst (2) abs_of_nonneg)
       
   962   apply force
       
   963   apply (rule gcd_lcm_distrib_nat [transferred])
       
   964   apply auto
       
   965 done
       
   966 
       
   967 end