merged
authorhuffman
Thu, 19 Nov 2009 22:30:14 -0800
changeset 33811 b1b66441275d
parent 33810 38375b16ffd9 (current diff)
parent 33806 dfca0f0e6397 (diff)
child 33812 10c335383c8b
merged
--- a/src/HOL/Divides.thy	Thu Nov 19 22:28:36 2009 -0800
+++ b/src/HOL/Divides.thy	Thu Nov 19 22:30:14 2009 -0800
@@ -2157,6 +2157,10 @@
 lemma div_nonpos_pos_le0: "[| (a::int) \<le> 0; b > 0 |] ==> a div b \<le> 0"
 by (drule zdiv_mono1, auto)
 
+text{* Now for some equivalences of the form @{text"a div b >=< 0 \<longleftrightarrow> \<dots>"}
+conditional upon the sign of @{text a} or @{text b}. There are many more.
+They should all be simp rules unless that causes too much search. *}
+
 lemma pos_imp_zdiv_nonneg_iff: "(0::int) < b ==> (0 \<le> a div b) = (0 \<le> a)"
 apply auto
 apply (drule_tac [2] zdiv_mono1)
@@ -2166,7 +2170,7 @@
 done
 
 lemma neg_imp_zdiv_nonneg_iff:
-     "b < (0::int) ==> (0 \<le> a div b) = (a \<le> (0::int))"
+  "b < (0::int) ==> (0 \<le> a div b) = (a \<le> (0::int))"
 apply (subst zdiv_zminus_zminus [symmetric])
 apply (subst pos_imp_zdiv_nonneg_iff, auto)
 done
@@ -2179,6 +2183,16 @@
 lemma neg_imp_zdiv_neg_iff: "b < (0::int) ==> (a div b < 0) = (0 < a)"
 by (simp add: linorder_not_le [symmetric] neg_imp_zdiv_nonneg_iff)
 
+lemma nonneg1_imp_zdiv_pos_iff:
+  "(0::int) <= a \<Longrightarrow> (a div b > 0) = (a >= b & b>0)"
+apply rule
+ apply rule
+  using div_pos_pos_trivial[of a b]apply arith
+ apply(cases "b=0")apply simp
+ using div_nonneg_neg_le0[of a b]apply arith
+using int_one_le_iff_zero_less[of "a div b"] zdiv_mono1[of b a b]apply simp
+done
+
 
 subsubsection {* The Divides Relation *}
 
--- a/src/HOL/Rational.thy	Thu Nov 19 22:28:36 2009 -0800
+++ b/src/HOL/Rational.thy	Thu Nov 19 22:30:14 2009 -0800
@@ -243,6 +243,166 @@
   with Fract `q = Fract a b` `b \<noteq> 0` show C by auto
 qed
 
+subsubsection {* Function @{text normalize} *}
+
+text{*
+Decompose a fraction into normalized, i.e. coprime numerator and denominator:
+*}
+
+definition normalize :: "rat \<Rightarrow> int \<times> int" where
+"normalize x \<equiv> THE pair. x = Fract (fst pair) (snd pair) &
+                   snd pair > 0 & gcd (fst pair) (snd pair) = 1"
+
+declare normalize_def[code del]
+
+lemma Fract_norm: "Fract (a div gcd a b) (b div gcd a b) = Fract a b"
+proof (cases "a = 0 | b = 0")
+  case True then show ?thesis by (auto simp add: eq_rat)
+next
+  let ?c = "gcd a b"
+  case False then have "a \<noteq> 0" and "b \<noteq> 0" by auto
+  then have "?c \<noteq> 0" by simp
+  then have "Fract ?c ?c = Fract 1 1" by (simp add: eq_rat)
+  moreover have "Fract (a div ?c * ?c + a mod ?c) (b div ?c * ?c + b mod ?c) = Fract a b"
+    by (simp add: semiring_div_class.mod_div_equality)
+  moreover have "a mod ?c = 0" by (simp add: dvd_eq_mod_eq_0 [symmetric])
+  moreover have "b mod ?c = 0" by (simp add: dvd_eq_mod_eq_0 [symmetric])
+  ultimately show ?thesis
+    by (simp add: mult_rat [symmetric])
+qed
+
+text{* Proof by Ren\'e Thiemann: *}
+lemma normalize_code[code]:
+"normalize (Fract a b) =
+ (if b > 0 then (let g = gcd a b in (a div g, b div g))
+  else if b = 0 then (0,1)
+  else (let g = - gcd a b in (a div g, b div g)))"
+proof -
+  let ?cond = "% r p. r = Fract (fst p) (snd p) & snd p > 0 &
+                 gcd (fst p) (snd p) = 1"
+  show ?thesis
+  proof (cases "b = 0")
+    case True
+    thus ?thesis
+    proof (simp add: normalize_def)
+      show "(THE pair. ?cond (Fract a 0) pair) = (0,1)"
+      proof
+        show "?cond (Fract a 0) (0,1)"
+          by (simp add: rat_number_collapse)
+      next
+        fix pair
+        assume cond: "?cond (Fract a 0) pair"
+        show "pair = (0,1)"
+        proof (cases pair)
+          case (Pair den num)
+          with cond have num: "num > 0" by auto
+          with Pair cond have den: "den = 0" by (simp add: eq_rat)
+          show ?thesis
+          proof (cases "num = 1", simp add: Pair den)
+            case False
+            with num have gr: "num > 1" by auto
+            with den have "gcd den num = num" by auto
+            with Pair cond False gr show ?thesis by auto
+          qed
+        qed
+      qed
+    qed
+  next
+    { fix a b :: int assume b: "b > 0"
+      hence b0: "b \<noteq> 0" and "b >= 0" by auto
+      let ?g = "gcd a b"
+      from b0 have g0: "?g \<noteq> 0" by auto
+      then have gp: "?g > 0" by simp
+      then have gs: "?g <= b" by (metis b gcd_le2_int)
+      from gcd_dvd1_int[of a b] obtain a' where a': "a = ?g * a'"
+        unfolding dvd_def by auto
+      from gcd_dvd2_int[of a b] obtain b' where b': "b = ?g * b'"
+        unfolding dvd_def by auto
+      hence b'2: "b' * ?g = b" by (simp add: ring_simps)
+      with b0 have b'0: "b' \<noteq> 0" by auto
+      from b b' zero_less_mult_iff[of ?g b'] gp have b'p: "b' > 0" by arith
+      have "normalize (Fract a b) = (a div ?g, b div ?g)"
+      proof (simp add: normalize_def)
+        show "(THE pair. ?cond (Fract a b) pair) = (a div ?g, b div ?g)"
+        proof
+          have "1 = b div b" using b0 by auto
+          also have "\<dots> <= b div ?g" by (rule zdiv_mono2[OF `b >= 0` gp gs])
+          finally have div0: "b div ?g > 0" by simp
+          show "?cond (Fract a b) (a div ?g, b div ?g)"
+            by (simp add: b0 Fract_norm div_gcd_coprime_int div0)
+        next
+          fix pair assume cond: "?cond (Fract a b) pair"
+          show "pair = (a div ?g, b div ?g)"
+          proof (cases pair)
+            case (Pair den num)
+            with cond
+            have num: "num > 0" and num0: "num \<noteq> 0" and gcd: "gcd den num = 1"
+              by auto
+            obtain g where g: "g = ?g" by auto
+            with gp have gg0: "g > 0" by auto
+            from cond Pair eq_rat(1)[OF b0 num0]
+            have eq: "a * num = den * b" by auto
+            hence "a' * g * num = den * g * b'"
+              using a'[simplified g[symmetric]] b'[simplified g[symmetric]]
+              by simp
+            hence "a' * num * g = b' * den * g" by (simp add: algebra_simps)
+            hence eq2: "a' * num = b' * den" using gg0 by auto
+            have "a div ?g = ?g * a' div ?g" using a' by force
+            hence adiv: "a div ?g = a'" using g0 by auto
+            have "b div ?g = ?g * b' div ?g" using b' by force
+            hence bdiv: "b div ?g = b'" using g0 by auto
+            from div_gcd_coprime_int[of a b] b0
+            have "gcd (a div ?g) (b div ?g) = 1" by auto
+            with adiv bdiv have gcd2: "gcd a' b' = 1" by auto
+            from gcd have gcd3: "gcd num den = 1"
+              by (simp add: gcd_commute_int[of den num])
+            from gcd2 have gcd4: "gcd b' a' = 1"
+              by (simp add: gcd_commute_int[of a' b'])
+            have one: "num dvd b'"
+              by (rule coprime_dvd_mult_int[OF gcd3], simp add: dvd_def, rule exI[of _ a'], simp add: eq2 algebra_simps)
+            have two: "b' dvd num" by (rule coprime_dvd_mult_int[OF gcd4], simp add: dvd_def, rule exI[of _ den], simp add: eq2 algebra_simps)
+            from one two
+            obtain k k' where k: "num = b' * k" and k': "b' = num * k'"
+              unfolding dvd_def by auto
+            hence "num = num * (k * k')" by (simp add: algebra_simps)
+            with num0 have prod: "k * k' = 1" by auto
+            from zero_less_mult_iff[of b' k] b'p num k have kp: "k > 0"
+              by auto
+            from prod pos_zmult_eq_1_iff[OF kp, of k'] have "k = 1" by auto
+            with k have numb': "num = b'" by auto
+            with eq2 b'0 have "a' = den" by auto
+            with numb' adiv bdiv Pair show ?thesis by simp
+          qed
+        qed
+      qed
+    }
+    note main = this
+    assume "b \<noteq> 0"
+    hence "b > 0 | b < 0" by arith
+    thus ?thesis
+    proof
+      assume b: "b > 0" thus ?thesis by (simp add: Let_def main[OF b])
+    next
+      assume b: "b < 0"
+      thus ?thesis
+        by(simp add:main Let_def minus_rat_cancel[of a b, symmetric]
+                    zdiv_zminus2 del:minus_rat_cancel)
+    qed
+  qed
+qed
+
+lemma normalize_id: "normalize (Fract a b) = (p,q) \<Longrightarrow> Fract p q = Fract a b"
+by(auto simp add: normalize_code Let_def Fract_norm dvd_div_neg rat_number_collapse
+        split:split_if_asm)
+
+lemma normalize_denom_pos: "normalize (Fract a b) = (p,q) \<Longrightarrow> q > 0"
+by(auto simp add: normalize_code Let_def dvd_div_neg pos_imp_zdiv_neg_iff nonneg1_imp_zdiv_pos_iff
+        split:split_if_asm)
+
+lemma normalize_coprime: "normalize (Fract a b) = (p,q) \<Longrightarrow> coprime p q"
+by(auto simp add: normalize_code Let_def dvd_div_neg div_gcd_coprime_int
+        split:split_if_asm)
+
 
 subsubsection {* The field of rational numbers *}
 
@@ -851,22 +1011,6 @@
 
 subsection {* Implementation of rational numbers as pairs of integers *}
 
-lemma Fract_norm: "Fract (a div gcd a b) (b div gcd a b) = Fract a b"
-proof (cases "a = 0 \<or> b = 0")
-  case True then show ?thesis by (auto simp add: eq_rat)
-next
-  let ?c = "gcd a b"
-  case False then have "a \<noteq> 0" and "b \<noteq> 0" by auto
-  then have "?c \<noteq> 0" by simp
-  then have "Fract ?c ?c = Fract 1 1" by (simp add: eq_rat)
-  moreover have "Fract (a div ?c * ?c + a mod ?c) (b div ?c * ?c + b mod ?c) = Fract a b"
-    by (simp add: semiring_div_class.mod_div_equality)
-  moreover have "a mod ?c = 0" by (simp add: dvd_eq_mod_eq_0 [symmetric])
-  moreover have "b mod ?c = 0" by (simp add: dvd_eq_mod_eq_0 [symmetric])
-  ultimately show ?thesis
-    by (simp add: mult_rat [symmetric])
-qed
-
 definition Fract_norm :: "int \<Rightarrow> int \<Rightarrow> rat" where
   [simp, code del]: "Fract_norm a b = Fract a b"