haftmann@35372: (* Title: HOL/Rat.thy paulson@14365: Author: Markus Wenzel, TU Muenchen paulson@14365: *) paulson@14365: wenzelm@14691: header {* Rational numbers *} paulson@14365: haftmann@35372: theory Rat huffman@30097: imports GCD Archimedean_Field huffman@35343: uses ("Tools/float_syntax.ML") nipkow@15131: begin paulson@14365: haftmann@27551: subsection {* Rational numbers as quotient *} paulson@14365: haftmann@27551: subsubsection {* Construction of the type of rational numbers *} huffman@18913: wenzelm@21404: definition wenzelm@21404: ratrel :: "((int \ int) \ (int \ int)) set" where haftmann@27551: "ratrel = {(x, y). snd x \ 0 \ snd y \ 0 \ fst x * snd y = fst y * snd x}" paulson@14365: huffman@18913: lemma ratrel_iff [simp]: haftmann@27551: "(x, y) \ ratrel \ snd x \ 0 \ snd y \ 0 \ fst x * snd y = fst y * snd x" haftmann@27551: by (simp add: ratrel_def) paulson@14365: nipkow@30198: lemma refl_on_ratrel: "refl_on {x. snd x \ 0} ratrel" nipkow@30198: by (auto simp add: refl_on_def ratrel_def) huffman@18913: huffman@18913: lemma sym_ratrel: "sym ratrel" haftmann@27551: by (simp add: ratrel_def sym_def) paulson@14365: huffman@18913: lemma trans_ratrel: "trans ratrel" haftmann@27551: proof (rule transI, unfold split_paired_all) haftmann@27551: fix a b a' b' a'' b'' :: int haftmann@27551: assume A: "((a, b), (a', b')) \ ratrel" haftmann@27551: assume B: "((a', b'), (a'', b'')) \ ratrel" haftmann@27551: have "b' * (a * b'') = b'' * (a * b')" by simp haftmann@27551: also from A have "a * b' = a' * b" by auto haftmann@27551: also have "b'' * (a' * b) = b * (a' * b'')" by simp haftmann@27551: also from B have "a' * b'' = a'' * b'" by auto haftmann@27551: also have "b * (a'' * b') = b' * (a'' * b)" by simp haftmann@27551: finally have "b' * (a * b'') = b' * (a'' * b)" . haftmann@27551: moreover from B have "b' \ 0" by auto haftmann@27551: ultimately have "a * b'' = a'' * b" by simp haftmann@27551: with A B show "((a, b), (a'', b'')) \ ratrel" by auto paulson@14365: qed haftmann@27551: haftmann@27551: lemma equiv_ratrel: "equiv {x. snd x \ 0} ratrel" haftmann@40815: by (rule equivI [OF refl_on_ratrel sym_ratrel trans_ratrel]) paulson@14365: huffman@18913: lemmas UN_ratrel = UN_equiv_class [OF equiv_ratrel] huffman@18913: lemmas UN_ratrel2 = UN_equiv_class2 [OF equiv_ratrel equiv_ratrel] paulson@14365: haftmann@27551: lemma equiv_ratrel_iff [iff]: haftmann@27551: assumes "snd x \ 0" and "snd y \ 0" haftmann@27551: shows "ratrel `` {x} = ratrel `` {y} \ (x, y) \ ratrel" haftmann@27551: by (rule eq_equiv_class_iff, rule equiv_ratrel) (auto simp add: assms) paulson@14365: wenzelm@45694: definition "Rat = {x. snd x \ 0} // ratrel" wenzelm@45694: wenzelm@45694: typedef (open) rat = Rat wenzelm@45694: morphisms Rep_Rat Abs_Rat wenzelm@45694: unfolding Rat_def haftmann@27551: proof haftmann@27551: have "(0::int, 1::int) \ {x. snd x \ 0}" by simp haftmann@27551: then show "ratrel `` {(0, 1)} \ {x. snd x \ 0} // ratrel" by (rule quotientI) haftmann@27551: qed haftmann@27551: haftmann@27551: lemma ratrel_in_Rat [simp]: "snd x \ 0 \ ratrel `` {x} \ Rat" haftmann@27551: by (simp add: Rat_def quotientI) haftmann@27551: haftmann@27551: declare Abs_Rat_inject [simp] Abs_Rat_inverse [simp] haftmann@27551: haftmann@27551: haftmann@27551: subsubsection {* Representation and basic operations *} haftmann@27551: haftmann@27551: definition haftmann@27551: Fract :: "int \ int \ rat" where haftmann@35369: "Fract a b = Abs_Rat (ratrel `` {if b = 0 then (0, 1) else (a, b)})" haftmann@27551: haftmann@27551: lemma eq_rat: haftmann@27551: shows "\a b c d. b \ 0 \ d \ 0 \ Fract a b = Fract c d \ a * d = c * b" haftmann@27652: and "\a. Fract a 0 = Fract 0 1" haftmann@27652: and "\a c. Fract 0 a = Fract 0 c" haftmann@27551: by (simp_all add: Fract_def) haftmann@27551: haftmann@35369: lemma Rat_cases [case_names Fract, cases type: rat]: haftmann@35369: assumes "\a b. q = Fract a b \ b > 0 \ coprime a b \ C" haftmann@35369: shows C haftmann@35369: proof - haftmann@35369: obtain a b :: int where "q = Fract a b" and "b \ 0" haftmann@35369: by (cases q) (clarsimp simp add: Fract_def Rat_def quotient_def) haftmann@35369: let ?a = "a div gcd a b" haftmann@35369: let ?b = "b div gcd a b" haftmann@35369: from `b \ 0` have "?b * gcd a b = b" haftmann@35369: by (simp add: dvd_div_mult_self) haftmann@35369: with `b \ 0` have "?b \ 0" by auto haftmann@35369: from `q = Fract a b` `b \ 0` `?b \ 0` have q: "q = Fract ?a ?b" haftmann@35369: by (simp add: eq_rat dvd_div_mult mult_commute [of a]) haftmann@35369: from `b \ 0` have coprime: "coprime ?a ?b" haftmann@35369: by (auto intro: div_gcd_coprime_int) haftmann@35369: show C proof (cases "b > 0") haftmann@35369: case True haftmann@35369: note assms haftmann@35369: moreover note q haftmann@35369: moreover from True have "?b > 0" by (simp add: nonneg1_imp_zdiv_pos_iff) haftmann@35369: moreover note coprime haftmann@35369: ultimately show C . haftmann@35369: next haftmann@35369: case False haftmann@35369: note assms haftmann@35369: moreover from q have "q = Fract (- ?a) (- ?b)" by (simp add: Fract_def) haftmann@35369: moreover from False `b \ 0` have "- ?b > 0" by (simp add: pos_imp_zdiv_neg_iff) haftmann@35369: moreover from coprime have "coprime (- ?a) (- ?b)" by simp haftmann@35369: ultimately show C . haftmann@35369: qed haftmann@35369: qed haftmann@35369: haftmann@35369: lemma Rat_induct [case_names Fract, induct type: rat]: haftmann@35369: assumes "\a b. b > 0 \ coprime a b \ P (Fract a b)" haftmann@35369: shows "P q" haftmann@35369: using assms by (cases q) simp haftmann@35369: haftmann@31017: instantiation rat :: comm_ring_1 haftmann@25571: begin haftmann@25571: haftmann@25571: definition haftmann@35369: Zero_rat_def: "0 = Fract 0 1" paulson@14365: haftmann@25571: definition haftmann@35369: One_rat_def: "1 = Fract 1 1" huffman@18913: haftmann@25571: definition haftmann@35369: add_rat_def: haftmann@27551: "q + r = Abs_Rat (\x \ Rep_Rat q. \y \ Rep_Rat r. haftmann@27551: ratrel `` {(fst x * snd y + fst y * snd x, snd x * snd y)})" haftmann@27551: haftmann@27652: lemma add_rat [simp]: haftmann@27551: assumes "b \ 0" and "d \ 0" haftmann@27551: shows "Fract a b + Fract c d = Fract (a * d + c * b) (b * d)" haftmann@27551: proof - haftmann@27551: have "(\x y. ratrel``{(fst x * snd y + fst y * snd x, snd x * snd y)}) haftmann@27551: respects2 ratrel" haftmann@27551: by (rule equiv_ratrel [THEN congruent2_commuteI]) (simp_all add: left_distrib) haftmann@27551: with assms show ?thesis by (simp add: Fract_def add_rat_def UN_ratrel2) haftmann@27551: qed huffman@18913: haftmann@25571: definition haftmann@35369: minus_rat_def: haftmann@27551: "- q = Abs_Rat (\x \ Rep_Rat q. ratrel `` {(- fst x, snd x)})" haftmann@27551: haftmann@35369: lemma minus_rat [simp]: "- Fract a b = Fract (- a) b" haftmann@27551: proof - haftmann@27551: have "(\x. ratrel `` {(- fst x, snd x)}) respects ratrel" haftmann@40819: by (simp add: congruent_def split_paired_all) haftmann@27551: then show ?thesis by (simp add: Fract_def minus_rat_def UN_ratrel) haftmann@27551: qed haftmann@27551: haftmann@27652: lemma minus_rat_cancel [simp]: "Fract (- a) (- b) = Fract a b" haftmann@27551: by (cases "b = 0") (simp_all add: eq_rat) haftmann@25571: haftmann@25571: definition haftmann@35369: diff_rat_def: "q - r = q + - (r::rat)" huffman@18913: haftmann@27652: lemma diff_rat [simp]: haftmann@27551: assumes "b \ 0" and "d \ 0" haftmann@27551: shows "Fract a b - Fract c d = Fract (a * d - c * b) (b * d)" haftmann@27652: using assms by (simp add: diff_rat_def) haftmann@25571: haftmann@25571: definition haftmann@35369: mult_rat_def: haftmann@27551: "q * r = Abs_Rat (\x \ Rep_Rat q. \y \ Rep_Rat r. haftmann@27551: ratrel``{(fst x * fst y, snd x * snd y)})" paulson@14365: haftmann@27652: lemma mult_rat [simp]: "Fract a b * Fract c d = Fract (a * c) (b * d)" haftmann@27551: proof - haftmann@27551: have "(\x y. ratrel `` {(fst x * fst y, snd x * snd y)}) respects2 ratrel" haftmann@27551: by (rule equiv_ratrel [THEN congruent2_commuteI]) simp_all haftmann@27551: then show ?thesis by (simp add: Fract_def mult_rat_def UN_ratrel2) paulson@14365: qed paulson@14365: haftmann@27652: lemma mult_rat_cancel: haftmann@27551: assumes "c \ 0" haftmann@27551: shows "Fract (c * a) (c * b) = Fract a b" haftmann@27551: proof - haftmann@27551: from assms have "Fract c c = Fract 1 1" by (simp add: Fract_def) haftmann@27652: then show ?thesis by (simp add: mult_rat [symmetric]) haftmann@27551: qed huffman@27509: huffman@27509: instance proof chaieb@27668: fix q r s :: rat show "(q * r) * s = q * (r * s)" haftmann@27652: by (cases q, cases r, cases s) (simp add: eq_rat) haftmann@27551: next haftmann@27551: fix q r :: rat show "q * r = r * q" haftmann@27652: by (cases q, cases r) (simp add: eq_rat) haftmann@27551: next haftmann@27551: fix q :: rat show "1 * q = q" haftmann@27652: by (cases q) (simp add: One_rat_def eq_rat) haftmann@27551: next haftmann@27551: fix q r s :: rat show "(q + r) + s = q + (r + s)" nipkow@29667: by (cases q, cases r, cases s) (simp add: eq_rat algebra_simps) haftmann@27551: next haftmann@27551: fix q r :: rat show "q + r = r + q" haftmann@27652: by (cases q, cases r) (simp add: eq_rat) haftmann@27551: next haftmann@27551: fix q :: rat show "0 + q = q" haftmann@27652: by (cases q) (simp add: Zero_rat_def eq_rat) haftmann@27551: next haftmann@27551: fix q :: rat show "- q + q = 0" haftmann@27652: by (cases q) (simp add: Zero_rat_def eq_rat) haftmann@27551: next haftmann@27551: fix q r :: rat show "q - r = q + - r" haftmann@27652: by (cases q, cases r) (simp add: eq_rat) haftmann@27551: next haftmann@27551: fix q r s :: rat show "(q + r) * s = q * s + r * s" nipkow@29667: by (cases q, cases r, cases s) (simp add: eq_rat algebra_simps) haftmann@27551: next haftmann@27551: show "(0::rat) \ 1" by (simp add: Zero_rat_def One_rat_def eq_rat) huffman@27509: qed huffman@27509: huffman@27509: end huffman@27509: haftmann@27551: lemma of_nat_rat: "of_nat k = Fract (of_nat k) 1" haftmann@27652: by (induct k) (simp_all add: Zero_rat_def One_rat_def) haftmann@27551: haftmann@27551: lemma of_int_rat: "of_int k = Fract k 1" haftmann@27652: by (cases k rule: int_diff_cases) (simp add: of_nat_rat) haftmann@27551: haftmann@27551: lemma Fract_of_nat_eq: "Fract (of_nat k) 1 = of_nat k" haftmann@27551: by (rule of_nat_rat [symmetric]) haftmann@27551: haftmann@27551: lemma Fract_of_int_eq: "Fract k 1 = of_int k" haftmann@27551: by (rule of_int_rat [symmetric]) haftmann@27551: haftmann@35369: lemma rat_number_collapse: haftmann@27551: "Fract 0 k = 0" haftmann@27551: "Fract 1 1 = 1" huffman@47108: "Fract (numeral w) 1 = numeral w" huffman@47108: "Fract (neg_numeral w) 1 = neg_numeral w" haftmann@27551: "Fract k 0 = 0" huffman@47108: using Fract_of_int_eq [of "numeral w"] huffman@47108: using Fract_of_int_eq [of "neg_numeral w"] huffman@47108: by (simp_all add: Zero_rat_def One_rat_def eq_rat) haftmann@27551: huffman@47108: lemma rat_number_expand: haftmann@27551: "0 = Fract 0 1" haftmann@27551: "1 = Fract 1 1" huffman@47108: "numeral k = Fract (numeral k) 1" huffman@47108: "neg_numeral k = Fract (neg_numeral k) 1" haftmann@27551: by (simp_all add: rat_number_collapse) haftmann@27551: haftmann@27551: lemma Rat_cases_nonzero [case_names Fract 0]: haftmann@35369: assumes Fract: "\a b. q = Fract a b \ b > 0 \ a \ 0 \ coprime a b \ C" haftmann@27551: assumes 0: "q = 0 \ C" haftmann@27551: shows C haftmann@27551: proof (cases "q = 0") haftmann@27551: case True then show C using 0 by auto haftmann@27551: next haftmann@27551: case False haftmann@35369: then obtain a b where "q = Fract a b" and "b > 0" and "coprime a b" by (cases q) auto haftmann@27551: moreover with False have "0 \ Fract a b" by simp haftmann@35369: with `b > 0` have "a \ 0" by (simp add: Zero_rat_def eq_rat) haftmann@35369: with Fract `q = Fract a b` `b > 0` `coprime a b` show C by blast haftmann@27551: qed haftmann@27551: nipkow@33805: subsubsection {* Function @{text normalize} *} nipkow@33805: haftmann@35369: lemma Fract_coprime: "Fract (a div gcd a b) (b div gcd a b) = Fract a b" haftmann@35369: proof (cases "b = 0") haftmann@35369: case True then show ?thesis by (simp add: eq_rat) haftmann@35369: next haftmann@35369: case False haftmann@35369: moreover have "b div gcd a b * gcd a b = b" haftmann@35369: by (rule dvd_div_mult_self) simp haftmann@35369: ultimately have "b div gcd a b \ 0" by auto haftmann@35369: with False show ?thesis by (simp add: eq_rat dvd_div_mult mult_commute [of a]) haftmann@35369: qed nipkow@33805: haftmann@35369: definition normalize :: "int \ int \ int \ int" where haftmann@35369: "normalize p = (if snd p > 0 then (let a = gcd (fst p) (snd p) in (fst p div a, snd p div a)) haftmann@35369: else if snd p = 0 then (0, 1) haftmann@35369: else (let a = - gcd (fst p) (snd p) in (fst p div a, snd p div a)))" haftmann@35369: haftmann@35369: lemma normalize_crossproduct: haftmann@35369: assumes "q \ 0" "s \ 0" haftmann@35369: assumes "normalize (p, q) = normalize (r, s)" haftmann@35369: shows "p * s = r * q" haftmann@35369: proof - haftmann@35369: have aux: "p * gcd r s = sgn (q * s) * r * gcd p q \ q * gcd r s = sgn (q * s) * s * gcd p q \ p * s = q * r" haftmann@35369: proof - haftmann@35369: assume "p * gcd r s = sgn (q * s) * r * gcd p q" and "q * gcd r s = sgn (q * s) * s * gcd p q" haftmann@35369: then have "(p * gcd r s) * (sgn (q * s) * s * gcd p q) = (q * gcd r s) * (sgn (q * s) * r * gcd p q)" by simp haftmann@35369: with assms show "p * s = q * r" by (auto simp add: mult_ac sgn_times sgn_0_0) haftmann@35369: qed haftmann@35369: from assms show ?thesis haftmann@35369: by (auto simp add: normalize_def Let_def dvd_div_div_eq_mult mult_commute sgn_times split: if_splits intro: aux) nipkow@33805: qed nipkow@33805: haftmann@35369: lemma normalize_eq: "normalize (a, b) = (p, q) \ Fract p q = Fract a b" haftmann@35369: by (auto simp add: normalize_def Let_def Fract_coprime dvd_div_neg rat_number_collapse haftmann@35369: split:split_if_asm) haftmann@35369: haftmann@35369: lemma normalize_denom_pos: "normalize r = (p, q) \ q > 0" haftmann@35369: by (auto simp add: normalize_def Let_def dvd_div_neg pos_imp_zdiv_neg_iff nonneg1_imp_zdiv_pos_iff haftmann@35369: split:split_if_asm) haftmann@35369: haftmann@35369: lemma normalize_coprime: "normalize r = (p, q) \ coprime p q" haftmann@35369: by (auto simp add: normalize_def Let_def dvd_div_neg div_gcd_coprime_int haftmann@35369: split:split_if_asm) haftmann@35369: haftmann@35369: lemma normalize_stable [simp]: haftmann@35369: "q > 0 \ coprime p q \ normalize (p, q) = (p, q)" haftmann@35369: by (simp add: normalize_def) haftmann@35369: haftmann@35369: lemma normalize_denom_zero [simp]: haftmann@35369: "normalize (p, 0) = (0, 1)" haftmann@35369: by (simp add: normalize_def) haftmann@35369: haftmann@35369: lemma normalize_negative [simp]: haftmann@35369: "q < 0 \ normalize (p, q) = normalize (- p, - q)" haftmann@35369: by (simp add: normalize_def Let_def dvd_div_neg dvd_neg_div) haftmann@35369: haftmann@35369: text{* haftmann@35369: Decompose a fraction into normalized, i.e. coprime numerator and denominator: haftmann@35369: *} haftmann@35369: haftmann@35369: definition quotient_of :: "rat \ int \ int" where haftmann@35369: "quotient_of x = (THE pair. x = Fract (fst pair) (snd pair) & haftmann@35369: snd pair > 0 & coprime (fst pair) (snd pair))" haftmann@35369: haftmann@35369: lemma quotient_of_unique: haftmann@35369: "\!p. r = Fract (fst p) (snd p) \ snd p > 0 \ coprime (fst p) (snd p)" haftmann@35369: proof (cases r) haftmann@35369: case (Fract a b) haftmann@35369: then have "r = Fract (fst (a, b)) (snd (a, b)) \ snd (a, b) > 0 \ coprime (fst (a, b)) (snd (a, b))" by auto haftmann@35369: then show ?thesis proof (rule ex1I) haftmann@35369: fix p haftmann@35369: obtain c d :: int where p: "p = (c, d)" by (cases p) haftmann@35369: assume "r = Fract (fst p) (snd p) \ snd p > 0 \ coprime (fst p) (snd p)" haftmann@35369: with p have Fract': "r = Fract c d" "d > 0" "coprime c d" by simp_all haftmann@35369: have "c = a \ d = b" haftmann@35369: proof (cases "a = 0") haftmann@35369: case True with Fract Fract' show ?thesis by (simp add: eq_rat) haftmann@35369: next haftmann@35369: case False haftmann@35369: with Fract Fract' have *: "c * b = a * d" and "c \ 0" by (auto simp add: eq_rat) haftmann@35369: then have "c * b > 0 \ a * d > 0" by auto haftmann@35369: with `b > 0` `d > 0` have "a > 0 \ c > 0" by (simp add: zero_less_mult_iff) haftmann@35369: with `a \ 0` `c \ 0` have sgn: "sgn a = sgn c" by (auto simp add: not_less) haftmann@35369: from `coprime a b` `coprime c d` have "\a\ * \d\ = \c\ * \b\ \ \a\ = \c\ \ \d\ = \b\" haftmann@35369: by (simp add: coprime_crossproduct_int) haftmann@35369: with `b > 0` `d > 0` have "\a\ * d = \c\ * b \ \a\ = \c\ \ d = b" by simp haftmann@35369: then have "a * sgn a * d = c * sgn c * b \ a * sgn a = c * sgn c \ d = b" by (simp add: abs_sgn) haftmann@35369: with sgn * show ?thesis by (auto simp add: sgn_0_0) nipkow@33805: qed haftmann@35369: with p show "p = (a, b)" by simp nipkow@33805: qed nipkow@33805: qed nipkow@33805: haftmann@35369: lemma quotient_of_Fract [code]: haftmann@35369: "quotient_of (Fract a b) = normalize (a, b)" haftmann@35369: proof - haftmann@35369: have "Fract a b = Fract (fst (normalize (a, b))) (snd (normalize (a, b)))" (is ?Fract) haftmann@35369: by (rule sym) (auto intro: normalize_eq) haftmann@35369: moreover have "0 < snd (normalize (a, b))" (is ?denom_pos) haftmann@35369: by (cases "normalize (a, b)") (rule normalize_denom_pos, simp) haftmann@35369: moreover have "coprime (fst (normalize (a, b))) (snd (normalize (a, b)))" (is ?coprime) haftmann@35369: by (rule normalize_coprime) simp haftmann@35369: ultimately have "?Fract \ ?denom_pos \ ?coprime" by blast haftmann@35369: with quotient_of_unique have haftmann@35369: "(THE p. Fract a b = Fract (fst p) (snd p) \ 0 < snd p \ coprime (fst p) (snd p)) = normalize (a, b)" haftmann@35369: by (rule the1_equality) haftmann@35369: then show ?thesis by (simp add: quotient_of_def) haftmann@35369: qed haftmann@35369: haftmann@35369: lemma quotient_of_number [simp]: haftmann@35369: "quotient_of 0 = (0, 1)" haftmann@35369: "quotient_of 1 = (1, 1)" huffman@47108: "quotient_of (numeral k) = (numeral k, 1)" huffman@47108: "quotient_of (neg_numeral k) = (neg_numeral k, 1)" haftmann@35369: by (simp_all add: rat_number_expand quotient_of_Fract) nipkow@33805: haftmann@35369: lemma quotient_of_eq: "quotient_of (Fract a b) = (p, q) \ Fract p q = Fract a b" haftmann@35369: by (simp add: quotient_of_Fract normalize_eq) haftmann@35369: haftmann@35369: lemma quotient_of_denom_pos: "quotient_of r = (p, q) \ q > 0" haftmann@35369: by (cases r) (simp add: quotient_of_Fract normalize_denom_pos) haftmann@35369: haftmann@35369: lemma quotient_of_coprime: "quotient_of r = (p, q) \ coprime p q" haftmann@35369: by (cases r) (simp add: quotient_of_Fract normalize_coprime) nipkow@33805: haftmann@35369: lemma quotient_of_inject: haftmann@35369: assumes "quotient_of a = quotient_of b" haftmann@35369: shows "a = b" haftmann@35369: proof - haftmann@35369: obtain p q r s where a: "a = Fract p q" haftmann@35369: and b: "b = Fract r s" haftmann@35369: and "q > 0" and "s > 0" by (cases a, cases b) haftmann@35369: with assms show ?thesis by (simp add: eq_rat quotient_of_Fract normalize_crossproduct) haftmann@35369: qed haftmann@35369: haftmann@35369: lemma quotient_of_inject_eq: haftmann@35369: "quotient_of a = quotient_of b \ a = b" haftmann@35369: by (auto simp add: quotient_of_inject) nipkow@33805: haftmann@27551: haftmann@27551: subsubsection {* The field of rational numbers *} haftmann@27551: haftmann@36409: instantiation rat :: field_inverse_zero haftmann@27551: begin haftmann@27551: haftmann@27551: definition haftmann@35369: inverse_rat_def: haftmann@27551: "inverse q = Abs_Rat (\x \ Rep_Rat q. haftmann@27551: ratrel `` {if fst x = 0 then (0, 1) else (snd x, fst x)})" haftmann@27551: haftmann@27652: lemma inverse_rat [simp]: "inverse (Fract a b) = Fract b a" haftmann@27551: proof - haftmann@27551: have "(\x. ratrel `` {if fst x = 0 then (0, 1) else (snd x, fst x)}) respects ratrel" haftmann@27551: by (auto simp add: congruent_def mult_commute) haftmann@27551: then show ?thesis by (simp add: Fract_def inverse_rat_def UN_ratrel) huffman@27509: qed huffman@27509: haftmann@27551: definition haftmann@35369: divide_rat_def: "q / r = q * inverse (r::rat)" haftmann@27551: haftmann@27652: lemma divide_rat [simp]: "Fract a b / Fract c d = Fract (a * d) (b * c)" haftmann@27652: by (simp add: divide_rat_def) haftmann@27551: haftmann@27551: instance proof haftmann@27551: fix q :: rat haftmann@27551: assume "q \ 0" haftmann@27551: then show "inverse q * q = 1" by (cases q rule: Rat_cases_nonzero) huffman@35216: (simp_all add: rat_number_expand eq_rat) haftmann@27551: next haftmann@27551: fix q r :: rat haftmann@27551: show "q / r = q * inverse r" by (simp add: divide_rat_def) haftmann@36415: next haftmann@36415: show "inverse 0 = (0::rat)" by (simp add: rat_number_expand, simp add: rat_number_collapse) haftmann@36415: qed haftmann@27551: haftmann@27551: end haftmann@27551: haftmann@27551: haftmann@27551: subsubsection {* Various *} haftmann@27551: haftmann@27551: lemma Fract_of_int_quotient: "Fract k l = of_int k / of_int l" haftmann@27652: by (simp add: Fract_of_int_eq [symmetric]) haftmann@27551: huffman@47108: lemma Fract_add_one: "n \ 0 ==> Fract (m + n) n = Fract m n + 1" huffman@47108: by (simp add: rat_number_expand) haftmann@27551: haftmann@27551: haftmann@27551: subsubsection {* The ordered field of rational numbers *} huffman@27509: huffman@27509: instantiation rat :: linorder huffman@27509: begin huffman@27509: huffman@27509: definition haftmann@35369: le_rat_def: haftmann@39910: "q \ r \ the_elem (\x \ Rep_Rat q. \y \ Rep_Rat r. haftmann@27551: {(fst x * snd y) * (snd x * snd y) \ (fst y * snd x) * (snd x * snd y)})" haftmann@27551: haftmann@27652: lemma le_rat [simp]: haftmann@27551: assumes "b \ 0" and "d \ 0" haftmann@27551: shows "Fract a b \ Fract c d \ (a * d) * (b * d) \ (c * b) * (b * d)" haftmann@27551: proof - haftmann@27551: have "(\x y. {(fst x * snd y) * (snd x * snd y) \ (fst y * snd x) * (snd x * snd y)}) haftmann@27551: respects2 ratrel" haftmann@27551: proof (clarsimp simp add: congruent2_def) haftmann@27551: fix a b a' b' c d c' d'::int haftmann@27551: assume neq: "b \ 0" "b' \ 0" "d \ 0" "d' \ 0" haftmann@27551: assume eq1: "a * b' = a' * b" haftmann@27551: assume eq2: "c * d' = c' * d" haftmann@27551: haftmann@27551: let ?le = "\a b c d. ((a * d) * (b * d) \ (c * b) * (b * d))" haftmann@27551: { haftmann@27551: fix a b c d x :: int assume x: "x \ 0" haftmann@27551: have "?le a b c d = ?le (a * x) (b * x) c d" haftmann@27551: proof - haftmann@27551: from x have "0 < x * x" by (auto simp add: zero_less_mult_iff) haftmann@27551: hence "?le a b c d = haftmann@27551: ((a * d) * (b * d) * (x * x) \ (c * b) * (b * d) * (x * x))" haftmann@27551: by (simp add: mult_le_cancel_right) haftmann@27551: also have "... = ?le (a * x) (b * x) c d" haftmann@27551: by (simp add: mult_ac) haftmann@27551: finally show ?thesis . haftmann@27551: qed haftmann@27551: } note le_factor = this haftmann@27551: haftmann@27551: let ?D = "b * d" and ?D' = "b' * d'" haftmann@27551: from neq have D: "?D \ 0" by simp haftmann@27551: from neq have "?D' \ 0" by simp haftmann@27551: hence "?le a b c d = ?le (a * ?D') (b * ?D') c d" haftmann@27551: by (rule le_factor) chaieb@27668: also have "... = ((a * b') * ?D * ?D' * d * d' \ (c * d') * ?D * ?D' * b * b')" haftmann@27551: by (simp add: mult_ac) haftmann@27551: also have "... = ((a' * b) * ?D * ?D' * d * d' \ (c' * d) * ?D * ?D' * b * b')" haftmann@27551: by (simp only: eq1 eq2) haftmann@27551: also have "... = ?le (a' * ?D) (b' * ?D) c' d'" haftmann@27551: by (simp add: mult_ac) haftmann@27551: also from D have "... = ?le a' b' c' d'" haftmann@27551: by (rule le_factor [symmetric]) haftmann@27551: finally show "?le a b c d = ?le a' b' c' d'" . haftmann@27551: qed haftmann@27551: with assms show ?thesis by (simp add: Fract_def le_rat_def UN_ratrel2) haftmann@27551: qed huffman@27509: huffman@27509: definition haftmann@35369: less_rat_def: "z < (w::rat) \ z \ w \ z \ w" huffman@27509: haftmann@27652: lemma less_rat [simp]: haftmann@27551: assumes "b \ 0" and "d \ 0" haftmann@27551: shows "Fract a b < Fract c d \ (a * d) * (b * d) < (c * b) * (b * d)" haftmann@27652: using assms by (simp add: less_rat_def eq_rat order_less_le) huffman@27509: huffman@27509: instance proof paulson@14365: fix q r s :: rat paulson@14365: { paulson@14365: assume "q \ r" and "r \ s" haftmann@35369: then show "q \ s" haftmann@35369: proof (induct q, induct r, induct s) paulson@14365: fix a b c d e f :: int haftmann@35369: assume neq: "b > 0" "d > 0" "f > 0" paulson@14365: assume 1: "Fract a b \ Fract c d" and 2: "Fract c d \ Fract e f" paulson@14365: show "Fract a b \ Fract e f" paulson@14365: proof - paulson@14365: from neq obtain bb: "0 < b * b" and dd: "0 < d * d" and ff: "0 < f * f" paulson@14365: by (auto simp add: zero_less_mult_iff linorder_neq_iff) paulson@14365: have "(a * d) * (b * d) * (f * f) \ (c * b) * (b * d) * (f * f)" paulson@14365: proof - paulson@14365: from neq 1 have "(a * d) * (b * d) \ (c * b) * (b * d)" haftmann@27652: by simp paulson@14365: with ff show ?thesis by (simp add: mult_le_cancel_right) paulson@14365: qed chaieb@27668: also have "... = (c * f) * (d * f) * (b * b)" by algebra paulson@14365: also have "... \ (e * d) * (d * f) * (b * b)" paulson@14365: proof - paulson@14365: from neq 2 have "(c * f) * (d * f) \ (e * d) * (d * f)" haftmann@27652: by simp paulson@14365: with bb show ?thesis by (simp add: mult_le_cancel_right) paulson@14365: qed paulson@14365: finally have "(a * f) * (b * f) * (d * d) \ e * b * (b * f) * (d * d)" paulson@14365: by (simp only: mult_ac) paulson@14365: with dd have "(a * f) * (b * f) \ (e * b) * (b * f)" paulson@14365: by (simp add: mult_le_cancel_right) haftmann@27652: with neq show ?thesis by simp paulson@14365: qed paulson@14365: qed paulson@14365: next paulson@14365: assume "q \ r" and "r \ q" haftmann@35369: then show "q = r" haftmann@35369: proof (induct q, induct r) paulson@14365: fix a b c d :: int haftmann@35369: assume neq: "b > 0" "d > 0" paulson@14365: assume 1: "Fract a b \ Fract c d" and 2: "Fract c d \ Fract a b" paulson@14365: show "Fract a b = Fract c d" paulson@14365: proof - paulson@14365: from neq 1 have "(a * d) * (b * d) \ (c * b) * (b * d)" haftmann@27652: by simp paulson@14365: also have "... \ (a * d) * (b * d)" paulson@14365: proof - paulson@14365: from neq 2 have "(c * b) * (d * b) \ (a * d) * (d * b)" haftmann@27652: by simp paulson@14365: thus ?thesis by (simp only: mult_ac) paulson@14365: qed paulson@14365: finally have "(a * d) * (b * d) = (c * b) * (b * d)" . paulson@14365: moreover from neq have "b * d \ 0" by simp paulson@14365: ultimately have "a * d = c * b" by simp paulson@14365: with neq show ?thesis by (simp add: eq_rat) paulson@14365: qed paulson@14365: qed paulson@14365: next paulson@14365: show "q \ q" haftmann@27652: by (induct q) simp haftmann@27682: show "(q < r) = (q \ r \ \ r \ q)" haftmann@27682: by (induct q, induct r) (auto simp add: le_less mult_commute) paulson@14365: show "q \ r \ r \ q" huffman@18913: by (induct q, induct r) haftmann@27652: (simp add: mult_commute, rule linorder_linear) paulson@14365: } paulson@14365: qed paulson@14365: huffman@27509: end huffman@27509: haftmann@27551: instantiation rat :: "{distrib_lattice, abs_if, sgn_if}" haftmann@25571: begin haftmann@25571: haftmann@25571: definition haftmann@35369: abs_rat_def: "\q\ = (if q < 0 then -q else (q::rat))" haftmann@27551: haftmann@27652: lemma abs_rat [simp, code]: "\Fract a b\ = Fract \a\ \b\" huffman@35216: by (auto simp add: abs_rat_def zabs_def Zero_rat_def not_less le_less eq_rat zero_less_mult_iff) haftmann@27551: haftmann@27551: definition haftmann@35369: sgn_rat_def: "sgn (q::rat) = (if q = 0 then 0 else if 0 < q then 1 else - 1)" haftmann@27551: haftmann@27652: lemma sgn_rat [simp, code]: "sgn (Fract a b) = of_int (sgn a * sgn b)" haftmann@27551: unfolding Fract_of_int_eq haftmann@27652: by (auto simp: zsgn_def sgn_rat_def Zero_rat_def eq_rat) haftmann@27551: (auto simp: rat_number_collapse not_less le_less zero_less_mult_iff) haftmann@27551: haftmann@27551: definition haftmann@25571: "(inf \ rat \ rat \ rat) = min" haftmann@25571: haftmann@25571: definition haftmann@25571: "(sup \ rat \ rat \ rat) = max" haftmann@25571: haftmann@27551: instance by intro_classes haftmann@27551: (auto simp add: abs_rat_def sgn_rat_def min_max.sup_inf_distrib1 inf_rat_def sup_rat_def) haftmann@22456: haftmann@25571: end haftmann@25571: haftmann@36409: instance rat :: linordered_field_inverse_zero haftmann@27551: proof paulson@14365: fix q r s :: rat paulson@14365: show "q \ r ==> s + q \ s + r" paulson@14365: proof (induct q, induct r, induct s) paulson@14365: fix a b c d e f :: int haftmann@35369: assume neq: "b > 0" "d > 0" "f > 0" paulson@14365: assume le: "Fract a b \ Fract c d" paulson@14365: show "Fract e f + Fract a b \ Fract e f + Fract c d" paulson@14365: proof - paulson@14365: let ?F = "f * f" from neq have F: "0 < ?F" paulson@14365: by (auto simp add: zero_less_mult_iff) paulson@14365: from neq le have "(a * d) * (b * d) \ (c * b) * (b * d)" haftmann@27652: by simp paulson@14365: with F have "(a * d) * (b * d) * ?F * ?F \ (c * b) * (b * d) * ?F * ?F" paulson@14365: by (simp add: mult_le_cancel_right) haftmann@27652: with neq show ?thesis by (simp add: mult_ac int_distrib) paulson@14365: qed paulson@14365: qed paulson@14365: show "q < r ==> 0 < s ==> s * q < s * r" paulson@14365: proof (induct q, induct r, induct s) paulson@14365: fix a b c d e f :: int haftmann@35369: assume neq: "b > 0" "d > 0" "f > 0" paulson@14365: assume le: "Fract a b < Fract c d" paulson@14365: assume gt: "0 < Fract e f" paulson@14365: show "Fract e f * Fract a b < Fract e f * Fract c d" paulson@14365: proof - paulson@14365: let ?E = "e * f" and ?F = "f * f" paulson@14365: from neq gt have "0 < ?E" haftmann@27652: by (auto simp add: Zero_rat_def order_less_le eq_rat) paulson@14365: moreover from neq have "0 < ?F" paulson@14365: by (auto simp add: zero_less_mult_iff) paulson@14365: moreover from neq le have "(a * d) * (b * d) < (c * b) * (b * d)" haftmann@27652: by simp paulson@14365: ultimately have "(a * d) * (b * d) * ?E * ?F < (c * b) * (b * d) * ?E * ?F" paulson@14365: by (simp add: mult_less_cancel_right) paulson@14365: with neq show ?thesis haftmann@27652: by (simp add: mult_ac) paulson@14365: qed paulson@14365: qed haftmann@27551: qed auto paulson@14365: haftmann@27551: lemma Rat_induct_pos [case_names Fract, induct type: rat]: haftmann@27551: assumes step: "\a b. 0 < b \ P (Fract a b)" haftmann@27551: shows "P q" paulson@14365: proof (cases q) haftmann@27551: have step': "\a b. b < 0 \ P (Fract a b)" paulson@14365: proof - paulson@14365: fix a::int and b::int paulson@14365: assume b: "b < 0" paulson@14365: hence "0 < -b" by simp paulson@14365: hence "P (Fract (-a) (-b))" by (rule step) paulson@14365: thus "P (Fract a b)" by (simp add: order_less_imp_not_eq [OF b]) paulson@14365: qed paulson@14365: case (Fract a b) paulson@14365: thus "P q" by (force simp add: linorder_neq_iff step step') paulson@14365: qed paulson@14365: paulson@14365: lemma zero_less_Fract_iff: huffman@30095: "0 < b \ 0 < Fract a b \ 0 < a" huffman@30095: by (simp add: Zero_rat_def zero_less_mult_iff) huffman@30095: huffman@30095: lemma Fract_less_zero_iff: huffman@30095: "0 < b \ Fract a b < 0 \ a < 0" huffman@30095: by (simp add: Zero_rat_def mult_less_0_iff) huffman@30095: huffman@30095: lemma zero_le_Fract_iff: huffman@30095: "0 < b \ 0 \ Fract a b \ 0 \ a" huffman@30095: by (simp add: Zero_rat_def zero_le_mult_iff) huffman@30095: huffman@30095: lemma Fract_le_zero_iff: huffman@30095: "0 < b \ Fract a b \ 0 \ a \ 0" huffman@30095: by (simp add: Zero_rat_def mult_le_0_iff) huffman@30095: huffman@30095: lemma one_less_Fract_iff: huffman@30095: "0 < b \ 1 < Fract a b \ b < a" huffman@30095: by (simp add: One_rat_def mult_less_cancel_right_disj) huffman@30095: huffman@30095: lemma Fract_less_one_iff: huffman@30095: "0 < b \ Fract a b < 1 \ a < b" huffman@30095: by (simp add: One_rat_def mult_less_cancel_right_disj) huffman@30095: huffman@30095: lemma one_le_Fract_iff: huffman@30095: "0 < b \ 1 \ Fract a b \ b \ a" huffman@30095: by (simp add: One_rat_def mult_le_cancel_right) huffman@30095: huffman@30095: lemma Fract_le_one_iff: huffman@30095: "0 < b \ Fract a b \ 1 \ a \ b" huffman@30095: by (simp add: One_rat_def mult_le_cancel_right) paulson@14365: paulson@14378: huffman@30097: subsubsection {* Rationals are an Archimedean field *} huffman@30097: huffman@30097: lemma rat_floor_lemma: huffman@30097: shows "of_int (a div b) \ Fract a b \ Fract a b < of_int (a div b + 1)" huffman@30097: proof - huffman@30097: have "Fract a b = of_int (a div b) + Fract (a mod b) b" huffman@35293: by (cases "b = 0", simp, simp add: of_int_rat) huffman@30097: moreover have "0 \ Fract (a mod b) b \ Fract (a mod b) b < 1" huffman@35293: unfolding Fract_of_int_quotient haftmann@36409: by (rule linorder_cases [of b 0]) (simp add: divide_nonpos_neg, simp, simp add: divide_nonneg_pos) huffman@30097: ultimately show ?thesis by simp huffman@30097: qed huffman@30097: huffman@30097: instance rat :: archimedean_field huffman@30097: proof huffman@30097: fix r :: rat huffman@30097: show "\z. r \ of_int z" huffman@30097: proof (induct r) huffman@30097: case (Fract a b) huffman@35293: have "Fract a b \ of_int (a div b + 1)" huffman@35293: using rat_floor_lemma [of a b] by simp huffman@30097: then show "\z. Fract a b \ of_int z" .. huffman@30097: qed huffman@30097: qed huffman@30097: bulwahn@43732: instantiation rat :: floor_ceiling bulwahn@43732: begin bulwahn@43732: bulwahn@43732: definition [code del]: bulwahn@43732: "floor (x::rat) = (THE z. of_int z \ x \ x < of_int (z + 1))" bulwahn@43732: bulwahn@43732: instance proof bulwahn@43732: fix x :: rat bulwahn@43732: show "of_int (floor x) \ x \ x < of_int (floor x + 1)" bulwahn@43732: unfolding floor_rat_def using floor_exists1 by (rule theI') bulwahn@43732: qed bulwahn@43732: bulwahn@43732: end bulwahn@43732: huffman@35293: lemma floor_Fract: "floor (Fract a b) = a div b" huffman@35293: using rat_floor_lemma [of a b] huffman@30097: by (simp add: floor_unique) huffman@30097: huffman@30097: haftmann@31100: subsection {* Linear arithmetic setup *} paulson@14387: haftmann@31100: declaration {* haftmann@31100: K (Lin_Arith.add_inj_thms [@{thm of_nat_le_iff} RS iffD2, @{thm of_nat_eq_iff} RS iffD2] haftmann@31100: (* not needed because x < (y::nat) can be rewritten as Suc x <= y: of_nat_less_iff RS iffD2 *) haftmann@31100: #> Lin_Arith.add_inj_thms [@{thm of_int_le_iff} RS iffD2, @{thm of_int_eq_iff} RS iffD2] haftmann@31100: (* not needed because x < (y::int) can be rewritten as x + 1 <= y: of_int_less_iff RS iffD2 *) haftmann@31100: #> Lin_Arith.add_simps [@{thm neg_less_iff_less}, haftmann@31100: @{thm True_implies_equals}, huffman@47108: read_instantiate @{context} [(("a", 0), "(numeral ?v)")] @{thm right_distrib}, huffman@47108: read_instantiate @{context} [(("a", 0), "(neg_numeral ?v)")] @{thm right_distrib}, haftmann@31100: @{thm divide_1}, @{thm divide_zero_left}, haftmann@31100: @{thm times_divide_eq_right}, @{thm times_divide_eq_left}, haftmann@31100: @{thm minus_divide_left} RS sym, @{thm minus_divide_right} RS sym, haftmann@31100: @{thm of_int_minus}, @{thm of_int_diff}, haftmann@31100: @{thm of_int_of_nat_eq}] haftmann@31100: #> Lin_Arith.add_simprocs Numeral_Simprocs.field_cancel_numeral_factors haftmann@31100: #> Lin_Arith.add_inj_const (@{const_name of_nat}, @{typ "nat => rat"}) haftmann@31100: #> Lin_Arith.add_inj_const (@{const_name of_int}, @{typ "int => rat"})) haftmann@31100: *} paulson@14387: huffman@23342: huffman@23342: subsection {* Embedding from Rationals to other Fields *} huffman@23342: haftmann@24198: class field_char_0 = field + ring_char_0 huffman@23342: haftmann@35028: subclass (in linordered_field) field_char_0 .. huffman@23342: haftmann@27551: context field_char_0 haftmann@27551: begin haftmann@27551: haftmann@27551: definition of_rat :: "rat \ 'a" where haftmann@39910: "of_rat q = the_elem (\(a,b) \ Rep_Rat q. {of_int a / of_int b})" huffman@23342: haftmann@27551: end haftmann@27551: huffman@23342: lemma of_rat_congruent: haftmann@27551: "(\(a, b). {of_int a / of_int b :: 'a::field_char_0}) respects ratrel" haftmann@40816: apply (rule congruentI) huffman@23342: apply (clarsimp simp add: nonzero_divide_eq_eq nonzero_eq_divide_eq) huffman@23342: apply (simp only: of_int_mult [symmetric]) huffman@23342: done huffman@23342: haftmann@27551: lemma of_rat_rat: "b \ 0 \ of_rat (Fract a b) = of_int a / of_int b" haftmann@27551: unfolding Fract_def of_rat_def by (simp add: UN_ratrel of_rat_congruent) huffman@23342: huffman@23342: lemma of_rat_0 [simp]: "of_rat 0 = 0" huffman@23342: by (simp add: Zero_rat_def of_rat_rat) huffman@23342: huffman@23342: lemma of_rat_1 [simp]: "of_rat 1 = 1" huffman@23342: by (simp add: One_rat_def of_rat_rat) huffman@23342: huffman@23342: lemma of_rat_add: "of_rat (a + b) = of_rat a + of_rat b" haftmann@27652: by (induct a, induct b, simp add: of_rat_rat add_frac_eq) huffman@23342: huffman@23343: lemma of_rat_minus: "of_rat (- a) = - of_rat a" haftmann@27652: by (induct a, simp add: of_rat_rat) huffman@23343: huffman@23343: lemma of_rat_diff: "of_rat (a - b) = of_rat a - of_rat b" huffman@23343: by (simp only: diff_minus of_rat_add of_rat_minus) huffman@23343: huffman@23342: lemma of_rat_mult: "of_rat (a * b) = of_rat a * of_rat b" haftmann@27652: apply (induct a, induct b, simp add: of_rat_rat) huffman@23342: apply (simp add: divide_inverse nonzero_inverse_mult_distrib mult_ac) huffman@23342: done huffman@23342: huffman@23342: lemma nonzero_of_rat_inverse: huffman@23342: "a \ 0 \ of_rat (inverse a) = inverse (of_rat a)" huffman@23343: apply (rule inverse_unique [symmetric]) huffman@23343: apply (simp add: of_rat_mult [symmetric]) huffman@23342: done huffman@23342: huffman@23342: lemma of_rat_inverse: haftmann@36409: "(of_rat (inverse a)::'a::{field_char_0, field_inverse_zero}) = huffman@23342: inverse (of_rat a)" huffman@23342: by (cases "a = 0", simp_all add: nonzero_of_rat_inverse) huffman@23342: huffman@23342: lemma nonzero_of_rat_divide: huffman@23342: "b \ 0 \ of_rat (a / b) = of_rat a / of_rat b" huffman@23342: by (simp add: divide_inverse of_rat_mult nonzero_of_rat_inverse) huffman@23342: huffman@23342: lemma of_rat_divide: haftmann@36409: "(of_rat (a / b)::'a::{field_char_0, field_inverse_zero}) huffman@23342: = of_rat a / of_rat b" haftmann@27652: by (cases "b = 0") (simp_all add: nonzero_of_rat_divide) huffman@23342: huffman@23343: lemma of_rat_power: haftmann@31017: "(of_rat (a ^ n)::'a::field_char_0) = of_rat a ^ n" huffman@30273: by (induct n) (simp_all add: of_rat_mult) huffman@23343: huffman@23343: lemma of_rat_eq_iff [simp]: "(of_rat a = of_rat b) = (a = b)" huffman@23343: apply (induct a, induct b) huffman@23343: apply (simp add: of_rat_rat eq_rat) huffman@23343: apply (simp add: nonzero_divide_eq_eq nonzero_eq_divide_eq) huffman@23343: apply (simp only: of_int_mult [symmetric] of_int_eq_iff) huffman@23343: done huffman@23343: haftmann@27652: lemma of_rat_less: haftmann@35028: "(of_rat r :: 'a::linordered_field) < of_rat s \ r < s" haftmann@27652: proof (induct r, induct s) haftmann@27652: fix a b c d :: int haftmann@27652: assume not_zero: "b > 0" "d > 0" haftmann@27652: then have "b * d > 0" by (rule mult_pos_pos) haftmann@27652: have of_int_divide_less_eq: haftmann@27652: "(of_int a :: 'a) / of_int b < of_int c / of_int d haftmann@27652: \ (of_int a :: 'a) * of_int d < of_int c * of_int b" haftmann@27652: using not_zero by (simp add: pos_less_divide_eq pos_divide_less_eq) haftmann@35028: show "(of_rat (Fract a b) :: 'a::linordered_field) < of_rat (Fract c d) haftmann@27652: \ Fract a b < Fract c d" haftmann@27652: using not_zero `b * d > 0` haftmann@27652: by (simp add: of_rat_rat of_int_divide_less_eq of_int_mult [symmetric] del: of_int_mult) haftmann@27652: qed haftmann@27652: haftmann@27652: lemma of_rat_less_eq: haftmann@35028: "(of_rat r :: 'a::linordered_field) \ of_rat s \ r \ s" haftmann@27652: unfolding le_less by (auto simp add: of_rat_less) haftmann@27652: huffman@23343: lemmas of_rat_eq_0_iff [simp] = of_rat_eq_iff [of _ 0, simplified] huffman@23343: haftmann@27652: lemma of_rat_eq_id [simp]: "of_rat = id" huffman@23343: proof huffman@23343: fix a huffman@23343: show "of_rat a = id a" huffman@23343: by (induct a) haftmann@27652: (simp add: of_rat_rat Fract_of_int_eq [symmetric]) huffman@23343: qed huffman@23343: huffman@23343: text{*Collapse nested embeddings*} huffman@23343: lemma of_rat_of_nat_eq [simp]: "of_rat (of_nat n) = of_nat n" huffman@23343: by (induct n) (simp_all add: of_rat_add) huffman@23343: huffman@23343: lemma of_rat_of_int_eq [simp]: "of_rat (of_int z) = of_int z" haftmann@27652: by (cases z rule: int_diff_cases) (simp add: of_rat_diff) huffman@23343: huffman@47108: lemma of_rat_numeral_eq [simp]: huffman@47108: "of_rat (numeral w) = numeral w" huffman@47108: using of_rat_of_int_eq [of "numeral w"] by simp huffman@47108: huffman@47108: lemma of_rat_neg_numeral_eq [simp]: huffman@47108: "of_rat (neg_numeral w) = neg_numeral w" huffman@47108: using of_rat_of_int_eq [of "neg_numeral w"] by simp huffman@23343: haftmann@23879: lemmas zero_rat = Zero_rat_def haftmann@23879: lemmas one_rat = One_rat_def haftmann@23879: haftmann@24198: abbreviation haftmann@24198: rat_of_nat :: "nat \ rat" haftmann@24198: where haftmann@24198: "rat_of_nat \ of_nat" haftmann@24198: haftmann@24198: abbreviation haftmann@24198: rat_of_int :: "int \ rat" haftmann@24198: where haftmann@24198: "rat_of_int \ of_int" haftmann@24198: huffman@28010: subsection {* The Set of Rational Numbers *} berghofe@24533: nipkow@28001: context field_char_0 nipkow@28001: begin nipkow@28001: nipkow@28001: definition nipkow@28001: Rats :: "'a set" where haftmann@35369: "Rats = range of_rat" nipkow@28001: nipkow@28001: notation (xsymbols) nipkow@28001: Rats ("\") nipkow@28001: nipkow@28001: end nipkow@28001: huffman@28010: lemma Rats_of_rat [simp]: "of_rat r \ Rats" huffman@28010: by (simp add: Rats_def) huffman@28010: huffman@28010: lemma Rats_of_int [simp]: "of_int z \ Rats" huffman@28010: by (subst of_rat_of_int_eq [symmetric], rule Rats_of_rat) huffman@28010: huffman@28010: lemma Rats_of_nat [simp]: "of_nat n \ Rats" huffman@28010: by (subst of_rat_of_nat_eq [symmetric], rule Rats_of_rat) huffman@28010: huffman@47108: lemma Rats_number_of [simp]: "numeral w \ Rats" huffman@47108: by (subst of_rat_numeral_eq [symmetric], rule Rats_of_rat) huffman@47108: huffman@47108: lemma Rats_neg_number_of [simp]: "neg_numeral w \ Rats" huffman@47108: by (subst of_rat_neg_numeral_eq [symmetric], rule Rats_of_rat) huffman@28010: huffman@28010: lemma Rats_0 [simp]: "0 \ Rats" huffman@28010: apply (unfold Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_0 [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_1 [simp]: "1 \ Rats" huffman@28010: apply (unfold Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_1 [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_add [simp]: "\a \ Rats; b \ Rats\ \ a + b \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_add [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_minus [simp]: "a \ Rats \ - a \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_minus [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_diff [simp]: "\a \ Rats; b \ Rats\ \ a - b \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_diff [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_mult [simp]: "\a \ Rats; b \ Rats\ \ a * b \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_mult [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma nonzero_Rats_inverse: huffman@28010: fixes a :: "'a::field_char_0" huffman@28010: shows "\a \ Rats; a \ 0\ \ inverse a \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (erule nonzero_of_rat_inverse [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_inverse [simp]: haftmann@36409: fixes a :: "'a::{field_char_0, field_inverse_zero}" huffman@28010: shows "a \ Rats \ inverse a \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_inverse [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma nonzero_Rats_divide: huffman@28010: fixes a b :: "'a::field_char_0" huffman@28010: shows "\a \ Rats; b \ Rats; b \ 0\ \ a / b \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (erule nonzero_of_rat_divide [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_divide [simp]: haftmann@36409: fixes a b :: "'a::{field_char_0, field_inverse_zero}" huffman@28010: shows "\a \ Rats; b \ Rats\ \ a / b \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_divide [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_power [simp]: haftmann@31017: fixes a :: "'a::field_char_0" huffman@28010: shows "a \ Rats \ a ^ n \ Rats" huffman@28010: apply (auto simp add: Rats_def) huffman@28010: apply (rule range_eqI) huffman@28010: apply (rule of_rat_power [symmetric]) huffman@28010: done huffman@28010: huffman@28010: lemma Rats_cases [cases set: Rats]: huffman@28010: assumes "q \ \" huffman@28010: obtains (of_rat) r where "q = of_rat r" huffman@28010: unfolding Rats_def huffman@28010: proof - huffman@28010: from `q \ \` have "q \ range of_rat" unfolding Rats_def . huffman@28010: then obtain r where "q = of_rat r" .. huffman@28010: then show thesis .. huffman@28010: qed huffman@28010: huffman@28010: lemma Rats_induct [case_names of_rat, induct set: Rats]: huffman@28010: "q \ \ \ (\r. P (of_rat r)) \ P q" huffman@28010: by (rule Rats_cases) auto huffman@28010: nipkow@28001: berghofe@24533: subsection {* Implementation of rational numbers as pairs of integers *} berghofe@24533: huffman@47108: text {* Formal constructor *} huffman@47108: haftmann@35369: definition Frct :: "int \ int \ rat" where haftmann@35369: [simp]: "Frct p = Fract (fst p) (snd p)" haftmann@35369: haftmann@36112: lemma [code abstype]: haftmann@36112: "Frct (quotient_of q) = q" haftmann@36112: by (cases q) (auto intro: quotient_of_eq) haftmann@35369: huffman@47108: huffman@47108: text {* Numerals *} haftmann@35369: haftmann@35369: declare quotient_of_Fract [code abstract] haftmann@35369: huffman@47108: definition of_int :: "int \ rat" huffman@47108: where huffman@47108: [code_abbrev]: "of_int = Int.of_int" huffman@47108: hide_const (open) of_int huffman@47108: huffman@47108: lemma quotient_of_int [code abstract]: huffman@47108: "quotient_of (Rat.of_int a) = (a, 1)" huffman@47108: by (simp add: of_int_def of_int_rat quotient_of_Fract) huffman@47108: huffman@47108: lemma [code_unfold]: huffman@47108: "numeral k = Rat.of_int (numeral k)" huffman@47108: by (simp add: Rat.of_int_def) huffman@47108: huffman@47108: lemma [code_unfold]: huffman@47108: "neg_numeral k = Rat.of_int (neg_numeral k)" huffman@47108: by (simp add: Rat.of_int_def) huffman@47108: huffman@47108: lemma Frct_code_post [code_post]: huffman@47108: "Frct (0, a) = 0" huffman@47108: "Frct (a, 0) = 0" huffman@47108: "Frct (1, 1) = 1" huffman@47108: "Frct (numeral k, 1) = numeral k" huffman@47108: "Frct (neg_numeral k, 1) = neg_numeral k" huffman@47108: "Frct (1, numeral k) = 1 / numeral k" huffman@47108: "Frct (1, neg_numeral k) = 1 / neg_numeral k" huffman@47108: "Frct (numeral k, numeral l) = numeral k / numeral l" huffman@47108: "Frct (numeral k, neg_numeral l) = numeral k / neg_numeral l" huffman@47108: "Frct (neg_numeral k, numeral l) = neg_numeral k / numeral l" huffman@47108: "Frct (neg_numeral k, neg_numeral l) = neg_numeral k / neg_numeral l" huffman@47108: by (simp_all add: Fract_of_int_quotient) huffman@47108: huffman@47108: huffman@47108: text {* Operations *} huffman@47108: haftmann@35369: lemma rat_zero_code [code abstract]: haftmann@35369: "quotient_of 0 = (0, 1)" haftmann@35369: by (simp add: Zero_rat_def quotient_of_Fract normalize_def) haftmann@35369: haftmann@35369: lemma rat_one_code [code abstract]: haftmann@35369: "quotient_of 1 = (1, 1)" haftmann@35369: by (simp add: One_rat_def quotient_of_Fract normalize_def) haftmann@35369: haftmann@35369: lemma rat_plus_code [code abstract]: haftmann@35369: "quotient_of (p + q) = (let (a, c) = quotient_of p; (b, d) = quotient_of q haftmann@35369: in normalize (a * d + b * c, c * d))" haftmann@35369: by (cases p, cases q) (simp add: quotient_of_Fract) haftmann@27652: haftmann@35369: lemma rat_uminus_code [code abstract]: haftmann@35369: "quotient_of (- p) = (let (a, b) = quotient_of p in (- a, b))" haftmann@35369: by (cases p) (simp add: quotient_of_Fract) haftmann@35369: haftmann@35369: lemma rat_minus_code [code abstract]: haftmann@35369: "quotient_of (p - q) = (let (a, c) = quotient_of p; (b, d) = quotient_of q haftmann@35369: in normalize (a * d - b * c, c * d))" haftmann@35369: by (cases p, cases q) (simp add: quotient_of_Fract) haftmann@35369: haftmann@35369: lemma rat_times_code [code abstract]: haftmann@35369: "quotient_of (p * q) = (let (a, c) = quotient_of p; (b, d) = quotient_of q haftmann@35369: in normalize (a * b, c * d))" haftmann@35369: by (cases p, cases q) (simp add: quotient_of_Fract) berghofe@24533: haftmann@35369: lemma rat_inverse_code [code abstract]: haftmann@35369: "quotient_of (inverse p) = (let (a, b) = quotient_of p haftmann@35369: in if a = 0 then (0, 1) else (sgn a * b, \a\))" haftmann@35369: proof (cases p) haftmann@35369: case (Fract a b) then show ?thesis haftmann@35369: by (cases "0::int" a rule: linorder_cases) (simp_all add: quotient_of_Fract gcd_int.commute) haftmann@35369: qed haftmann@35369: haftmann@35369: lemma rat_divide_code [code abstract]: haftmann@35369: "quotient_of (p / q) = (let (a, c) = quotient_of p; (b, d) = quotient_of q haftmann@35369: in normalize (a * d, c * b))" haftmann@35369: by (cases p, cases q) (simp add: quotient_of_Fract) haftmann@35369: haftmann@35369: lemma rat_abs_code [code abstract]: haftmann@35369: "quotient_of \p\ = (let (a, b) = quotient_of p in (\a\, b))" haftmann@35369: by (cases p) (simp add: quotient_of_Fract) haftmann@35369: haftmann@35369: lemma rat_sgn_code [code abstract]: haftmann@35369: "quotient_of (sgn p) = (sgn (fst (quotient_of p)), 1)" haftmann@35369: proof (cases p) haftmann@35369: case (Fract a b) then show ?thesis haftmann@35369: by (cases "0::int" a rule: linorder_cases) (simp_all add: quotient_of_Fract) haftmann@35369: qed berghofe@24533: bulwahn@43733: lemma rat_floor_code [code]: bulwahn@43733: "floor p = (let (a, b) = quotient_of p in a div b)" bulwahn@43733: by (cases p) (simp add: quotient_of_Fract floor_Fract) bulwahn@43733: haftmann@38857: instantiation rat :: equal haftmann@26513: begin haftmann@26513: haftmann@35369: definition [code]: haftmann@38857: "HOL.equal a b \ quotient_of a = quotient_of b" haftmann@26513: haftmann@35369: instance proof haftmann@38857: qed (simp add: equal_rat_def quotient_of_inject_eq) haftmann@26513: haftmann@28351: lemma rat_eq_refl [code nbe]: haftmann@38857: "HOL.equal (r::rat) r \ True" haftmann@38857: by (rule equal_refl) haftmann@28351: haftmann@26513: end berghofe@24533: haftmann@35369: lemma rat_less_eq_code [code]: haftmann@35369: "p \ q \ (let (a, c) = quotient_of p; (b, d) = quotient_of q in a * d \ c * b)" haftmann@35726: by (cases p, cases q) (simp add: quotient_of_Fract mult.commute) berghofe@24533: haftmann@35369: lemma rat_less_code [code]: haftmann@35369: "p < q \ (let (a, c) = quotient_of p; (b, d) = quotient_of q in a * d < c * b)" haftmann@35726: by (cases p, cases q) (simp add: quotient_of_Fract mult.commute) berghofe@24533: haftmann@35369: lemma [code]: haftmann@35369: "of_rat p = (let (a, b) = quotient_of p in of_int a / of_int b)" haftmann@35369: by (cases p) (simp add: quotient_of_Fract of_rat_rat) haftmann@27652: huffman@47108: huffman@47108: text {* Quickcheck *} huffman@47108: haftmann@31203: definition (in term_syntax) haftmann@32657: valterm_fract :: "int \ (unit \ Code_Evaluation.term) \ int \ (unit \ Code_Evaluation.term) \ rat \ (unit \ Code_Evaluation.term)" where haftmann@32657: [code_unfold]: "valterm_fract k l = Code_Evaluation.valtermify Fract {\} k {\} l" haftmann@31203: haftmann@37751: notation fcomp (infixl "\>" 60) haftmann@37751: notation scomp (infixl "\\" 60) haftmann@31203: haftmann@31203: instantiation rat :: random haftmann@31203: begin haftmann@31203: haftmann@31203: definition haftmann@37751: "Quickcheck.random i = Quickcheck.random i \\ (\num. Random.range i \\ (\denom. Pair ( haftmann@31205: let j = Code_Numeral.int_of (denom + 1) haftmann@32657: in valterm_fract num (j, \u. Code_Evaluation.term_of j))))" haftmann@31203: haftmann@31203: instance .. haftmann@31203: haftmann@31203: end haftmann@31203: haftmann@37751: no_notation fcomp (infixl "\>" 60) haftmann@37751: no_notation scomp (infixl "\\" 60) haftmann@31203: bulwahn@41920: instantiation rat :: exhaustive bulwahn@41231: begin bulwahn@41231: bulwahn@41231: definition bulwahn@45818: "exhaustive_rat f d = Quickcheck_Exhaustive.exhaustive (%l. Quickcheck_Exhaustive.exhaustive (%k. f (Fract k (Code_Numeral.int_of l + 1))) d) d" bulwahn@42311: bulwahn@42311: instance .. bulwahn@42311: bulwahn@42311: end bulwahn@42311: bulwahn@42311: instantiation rat :: full_exhaustive bulwahn@42311: begin bulwahn@42311: bulwahn@42311: definition bulwahn@45818: "full_exhaustive_rat f d = Quickcheck_Exhaustive.full_exhaustive (%(l, _). Quickcheck_Exhaustive.full_exhaustive (%k. bulwahn@45507: f (let j = Code_Numeral.int_of l + 1 bulwahn@45507: in valterm_fract k (j, %_. Code_Evaluation.term_of j))) d) d" bulwahn@41231: bulwahn@41231: instance .. bulwahn@41231: bulwahn@41231: end bulwahn@41231: bulwahn@43889: instantiation rat :: partial_term_of bulwahn@43889: begin bulwahn@43889: bulwahn@43889: instance .. bulwahn@43889: bulwahn@43889: end bulwahn@43889: bulwahn@43889: lemma [code]: bulwahn@46758: "partial_term_of (ty :: rat itself) (Quickcheck_Narrowing.Narrowing_variable p tt) == Code_Evaluation.Free (STR ''_'') (Typerep.Typerep (STR ''Rat.rat'') [])" bulwahn@46758: "partial_term_of (ty :: rat itself) (Quickcheck_Narrowing.Narrowing_constructor 0 [l, k]) == bulwahn@45507: Code_Evaluation.App (Code_Evaluation.Const (STR ''Rat.Frct'') bulwahn@45507: (Typerep.Typerep (STR ''fun'') [Typerep.Typerep (STR ''Product_Type.prod'') [Typerep.Typerep (STR ''Int.int'') [], Typerep.Typerep (STR ''Int.int'') []], bulwahn@45507: Typerep.Typerep (STR ''Rat.rat'') []])) (Code_Evaluation.App (Code_Evaluation.App (Code_Evaluation.Const (STR ''Product_Type.Pair'') (Typerep.Typerep (STR ''fun'') [Typerep.Typerep (STR ''Int.int'') [], Typerep.Typerep (STR ''fun'') [Typerep.Typerep (STR ''Int.int'') [], Typerep.Typerep (STR ''Product_Type.prod'') [Typerep.Typerep (STR ''Int.int'') [], Typerep.Typerep (STR ''Int.int'') []]]])) (partial_term_of (TYPE(int)) l)) (partial_term_of (TYPE(int)) k))" bulwahn@43889: by (rule partial_term_of_anything)+ bulwahn@43889: bulwahn@43887: instantiation rat :: narrowing bulwahn@43887: begin bulwahn@43887: bulwahn@43887: definition bulwahn@45507: "narrowing = Quickcheck_Narrowing.apply (Quickcheck_Narrowing.apply bulwahn@45507: (Quickcheck_Narrowing.cons (%nom denom. Fract nom denom)) narrowing) narrowing" bulwahn@43887: bulwahn@43887: instance .. bulwahn@43887: bulwahn@43887: end bulwahn@43887: bulwahn@43887: bulwahn@45183: subsection {* Setup for Nitpick *} berghofe@24533: blanchet@38287: declaration {* blanchet@38287: Nitpick_HOL.register_frac_type @{type_name rat} wenzelm@33209: [(@{const_name zero_rat_inst.zero_rat}, @{const_name Nitpick.zero_frac}), wenzelm@33209: (@{const_name one_rat_inst.one_rat}, @{const_name Nitpick.one_frac}), wenzelm@33209: (@{const_name plus_rat_inst.plus_rat}, @{const_name Nitpick.plus_frac}), wenzelm@33209: (@{const_name times_rat_inst.times_rat}, @{const_name Nitpick.times_frac}), wenzelm@33209: (@{const_name uminus_rat_inst.uminus_rat}, @{const_name Nitpick.uminus_frac}), wenzelm@33209: (@{const_name inverse_rat_inst.inverse_rat}, @{const_name Nitpick.inverse_frac}), blanchet@37397: (@{const_name ord_rat_inst.less_rat}, @{const_name Nitpick.less_frac}), wenzelm@33209: (@{const_name ord_rat_inst.less_eq_rat}, @{const_name Nitpick.less_eq_frac}), blanchet@45478: (@{const_name field_char_0_class.of_rat}, @{const_name Nitpick.of_frac})] blanchet@33197: *} blanchet@33197: blanchet@41792: lemmas [nitpick_unfold] = inverse_rat_inst.inverse_rat huffman@47108: one_rat_inst.one_rat ord_rat_inst.less_rat blanchet@37397: ord_rat_inst.less_eq_rat plus_rat_inst.plus_rat times_rat_inst.times_rat blanchet@37397: uminus_rat_inst.uminus_rat zero_rat_inst.zero_rat blanchet@33197: huffman@35343: subsection{* Float syntax *} huffman@35343: huffman@35343: syntax "_Float" :: "float_const \ 'a" ("_") huffman@35343: huffman@35343: use "Tools/float_syntax.ML" huffman@35343: setup Float_Syntax.setup huffman@35343: huffman@35343: text{* Test: *} huffman@35343: lemma "123.456 = -111.111 + 200 + 30 + 4 + 5/10 + 6/100 + (7/1000::rat)" huffman@35343: by simp huffman@35343: wenzelm@37143: wenzelm@37143: hide_const (open) normalize wenzelm@37143: huffman@29880: end