diff -r be91db94e526 -r 64e8d4afcf10 src/HOL/Divides.thy --- a/src/HOL/Divides.thy Thu Sep 29 14:15:01 2022 +0200 +++ b/src/HOL/Divides.thy Thu Sep 29 14:03:40 2022 +0000 @@ -1,537 +1,12 @@ (* Title: HOL/Divides.thy - Author: Lawrence C Paulson, Cambridge University Computer Laboratory - Copyright 1999 University of Cambridge *) -section \More on quotient and remainder\ +section \Lemmas of doubtful value\ theory Divides imports Parity begin -subsection \More on division\ - -subsubsection \Monotonicity in the First Argument (Dividend)\ - -lemma unique_quotient_lemma: - assumes "b * q' + r' \ b * q + r" "0 \ r'" "r' < b" "r < b" shows "q' \ (q::int)" -proof - - have "r' + b * (q'-q) \ r" - using assms by (simp add: right_diff_distrib) - moreover have "0 < b * (1 + q - q') " - using assms by (simp add: right_diff_distrib distrib_left) - moreover have "b * q' < b * (1 + q)" - using assms by (simp add: right_diff_distrib distrib_left) - ultimately show ?thesis - using assms by (simp add: mult_less_cancel_left) -qed - -lemma unique_quotient_lemma_neg: - "b * q' + r' \ b*q + r \ r \ 0 \ b < r \ b < r' \ q \ (q'::int)" - using unique_quotient_lemma[where b = "-b" and r = "-r'" and r'="-r"] by auto - -lemma zdiv_mono1: - \a div b \ a' div b\ - if \a \ a'\ \0 < b\ - for a b b' :: int -proof (rule unique_quotient_lemma) - show "b * (a div b) + a mod b \ b * (a' div b) + a' mod b" - using \a \ a'\ by auto -qed (use that in auto) - -lemma zdiv_mono1_neg: - fixes b::int - assumes "a \ a'" "b < 0" shows "a' div b \ a div b" -proof (rule unique_quotient_lemma_neg) - show "b * (a div b) + a mod b \ b * (a' div b) + a' mod b" - using assms(1) by auto -qed (use assms in auto) - - -subsubsection \Monotonicity in the Second Argument (Divisor)\ - -lemma q_pos_lemma: - fixes q'::int - assumes "0 \ b'*q' + r'" "r' < b'" "0 < b'" - shows "0 \ q'" -proof - - have "0 < b'* (q' + 1)" - using assms by (simp add: distrib_left) - with assms show ?thesis - by (simp add: zero_less_mult_iff) -qed - -lemma zdiv_mono2_lemma: - fixes q'::int - assumes eq: "b*q + r = b'*q' + r'" and le: "0 \ b'*q' + r'" and "r' < b'" "0 \ r" "0 < b'" "b' \ b" - shows "q \ q'" -proof - - have "0 \ q'" - using q_pos_lemma le \r' < b'\ \0 < b'\ by blast - moreover have "b*q = r' - r + b'*q'" - using eq by linarith - ultimately have "b*q < b* (q' + 1)" - using mult_right_mono assms unfolding distrib_left by fastforce - with assms show ?thesis - by (simp add: mult_less_cancel_left_pos) -qed - -lemma zdiv_mono2: - fixes a::int - assumes "0 \ a" "0 < b'" "b' \ b" shows "a div b \ a div b'" -proof (rule zdiv_mono2_lemma) - have "b \ 0" - using assms by linarith - show "b * (a div b) + a mod b = b' * (a div b') + a mod b'" - by simp -qed (use assms in auto) - -lemma zdiv_mono2_neg_lemma: - fixes q'::int - assumes "b*q + r = b'*q' + r'" "b'*q' + r' < 0" "r < b" "0 \ r'" "0 < b'" "b' \ b" - shows "q' \ q" -proof - - have "b'*q' < 0" - using assms by linarith - with assms have "q' \ 0" - by (simp add: mult_less_0_iff) - have "b*q' \ b'*q'" - by (simp add: \q' \ 0\ assms(6) mult_right_mono_neg) - then have "b*q' < b* (q + 1)" - using assms by (simp add: distrib_left) - then show ?thesis - using assms by (simp add: mult_less_cancel_left) -qed - -lemma zdiv_mono2_neg: - fixes a::int - assumes "a < 0" "0 < b'" "b' \ b" shows "a div b' \ a div b" -proof (rule zdiv_mono2_neg_lemma) - have "b \ 0" - using assms by linarith - show "b * (a div b) + a mod b = b' * (a div b') + a mod b'" - by simp -qed (use assms in auto) - - -subsubsection \Quotients of Signs\ - -lemma div_eq_minus1: "0 < b \ - 1 div b = - 1" for b :: int - by (simp add: divide_int_def) - -lemma zmod_minus1: "0 < b \ - 1 mod b = b - 1" for b :: int - by (auto simp add: modulo_int_def) - -lemma minus_mod_int_eq: - \- k mod l = l - 1 - (k - 1) mod l\ if \l \ 0\ for k l :: int -proof (cases \l = 0\) - case True - then show ?thesis - by simp -next - case False - with that have \l > 0\ - by simp - then show ?thesis - proof (cases \l dvd k\) - case True - then obtain j where \k = l * j\ .. - moreover have \(l * j mod l - 1) mod l = l - 1\ - using \l > 0\ by (simp add: zmod_minus1) - then have \(l * j - 1) mod l = l - 1\ - by (simp only: mod_simps) - ultimately show ?thesis - by simp - next - case False - moreover have 1: \0 < k mod l\ - using \0 < l\ False le_less by fastforce - moreover have 2: \k mod l < 1 + l\ - using \0 < l\ pos_mod_bound[of l k] by linarith - from 1 2 \l > 0\ have \(k mod l - 1) mod l = k mod l - 1\ - by (simp add: zmod_trivial_iff) - ultimately show ?thesis - by (simp only: zmod_zminus1_eq_if) - (simp add: mod_eq_0_iff_dvd algebra_simps mod_simps) - qed -qed - -lemma div_neg_pos_less0: - fixes a::int - assumes "a < 0" "0 < b" - shows "a div b < 0" -proof - - have "a div b \ - 1 div b" - using zdiv_mono1 assms by auto - also have "... \ -1" - by (simp add: assms(2) div_eq_minus1) - finally show ?thesis - by force -qed - -lemma div_nonneg_neg_le0: "[| (0::int) \ a; b < 0 |] ==> a div b \ 0" - by (drule zdiv_mono1_neg, auto) - -lemma div_nonpos_pos_le0: "[| (a::int) \ 0; b > 0 |] ==> a div b \ 0" - by (drule zdiv_mono1, auto) - -text\Now for some equivalences of the form \a div b >=< 0 \ \\ -conditional upon the sign of \a\ or \b\. There are many more. -They should all be simp rules unless that causes too much search.\ - -lemma pos_imp_zdiv_nonneg_iff: - fixes a::int - assumes "0 < b" - shows "(0 \ a div b) = (0 \ a)" -proof - show "0 \ a div b \ 0 \ a" - using assms - by (simp add: linorder_not_less [symmetric]) (blast intro: div_neg_pos_less0) -next - assume "0 \ a" - then have "0 div b \ a div b" - using zdiv_mono1 assms by blast - then show "0 \ a div b" - by auto -qed - -lemma pos_imp_zdiv_pos_iff: - "0 0 < (i::int) div k \ k \ i" - using pos_imp_zdiv_nonneg_iff[of k i] zdiv_eq_0_iff[of i k] by arith - -lemma neg_imp_zdiv_nonneg_iff: - fixes a::int - assumes "b < 0" - shows "(0 \ a div b) = (a \ 0)" - using assms by (simp add: div_minus_minus [of a, symmetric] pos_imp_zdiv_nonneg_iff del: div_minus_minus) - -(*But not (a div b \ 0 iff a\0); consider a=1, b=2 when a div b = 0.*) -lemma pos_imp_zdiv_neg_iff: "(0::int) < b ==> (a div b < 0) = (a < 0)" - by (simp add: linorder_not_le [symmetric] pos_imp_zdiv_nonneg_iff) - -(*Again the law fails for \: consider a = -1, b = -2 when a div b = 0*) -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: - fixes a::int - assumes "0 \ a" - shows "a div b > 0 \ a \ b \ b>0" -proof - - have "0 < a div b \ b \ a" - using div_pos_pos_trivial[of a b] assms by arith - moreover have "0 < a div b \ b > 0" - using assms div_nonneg_neg_le0[of a b] by(cases "b=0"; force) - moreover have "b \ a \ 0 < b \ 0 < a div b" - using int_one_le_iff_zero_less[of "a div b"] zdiv_mono1[of b a b] by simp - ultimately show ?thesis - by blast -qed - -lemma zmod_le_nonneg_dividend: "(m::int) \ 0 \ m mod k \ m" - by (rule split_zmod[THEN iffD2]) (fastforce dest: q_pos_lemma intro: split_mult_pos_le) - -lemma sgn_div_eq_sgn_mult: - \sgn (k div l) = of_bool (k div l \ 0) * sgn (k * l)\ - for k l :: int -proof (cases \k div l = 0\) - case True - then show ?thesis - by simp -next - case False - have \0 \ \k\ div \l\\ - by (cases \l = 0\) (simp_all add: pos_imp_zdiv_nonneg_iff) - then have \\k\ div \l\ \ 0 \ 0 < \k\ div \l\\ - by (simp add: less_le) - also have \\ \ \k\ \ \l\\ - using False nonneg1_imp_zdiv_pos_iff by auto - finally have *: \\k\ div \l\ \ 0 \ \l\ \ \k\\ . - show ?thesis - using \0 \ \k\ div \l\\ False - by (auto simp add: div_eq_div_abs [of k l] div_eq_sgn_abs [of k l] - sgn_mult sgn_1_pos sgn_1_neg sgn_eq_0_iff nonneg1_imp_zdiv_pos_iff * dest: sgn_not_eq_imp) -qed - -lemma - fixes a b q r :: int - assumes \a = b * q + r\ \0 \ r\ \r < b\ - shows int_div_pos_eq: - \a div b = q\ (is ?Q) - and int_mod_pos_eq: - \a mod b = r\ (is ?R) -proof - - from assms have \(a div b, a mod b) = (q, r)\ - by (cases b q r a rule: euclidean_relation_intI) - (auto simp add: ac_simps dvd_add_left_iff sgn_1_pos le_less dest: zdvd_imp_le) - then show ?Q and ?R - by simp_all -qed - -lemma int_div_neg_eq: - \a div b = q\ if \a = b * q + r\ \r \ 0\ \b < r\ for a b q r :: int - using that int_div_pos_eq [of a \- b\ \- q\ \- r\] by simp_all - -lemma int_mod_neg_eq: - \a mod b = r\ if \a = b * q + r\ \r \ 0\ \b < r\ for a b q r :: int - using that int_div_neg_eq [of a b q r] by simp - - -subsubsection \Further properties\ - -lemma div_int_pos_iff: - "k div l \ 0 \ k = 0 \ l = 0 \ k \ 0 \ l \ 0 - \ k < 0 \ l < 0" - for k l :: int -proof (cases "k = 0 \ l = 0") - case False - then have *: "k \ 0" "l \ 0" - by auto - then have "0 \ k div l \ \ k < 0 \ 0 \ l" - by (meson neg_imp_zdiv_neg_iff not_le not_less_iff_gr_or_eq) - then show ?thesis - using * by (auto simp add: pos_imp_zdiv_nonneg_iff neg_imp_zdiv_nonneg_iff) -qed auto - -lemma mod_int_pos_iff: - "k mod l \ 0 \ l dvd k \ l = 0 \ k \ 0 \ l > 0" - for k l :: int -proof (cases "l > 0") - case False - then show ?thesis - by (simp add: dvd_eq_mod_eq_0) (use neg_mod_sign [of l k] in \auto simp add: le_less not_less\) -qed auto - -text \Simplify expressions in which div and mod combine numerical constants\ - -lemma abs_div: "(y::int) dvd x \ \x div y\ = \x\ div \y\" - unfolding dvd_def by (cases "y=0") (auto simp add: abs_mult) - -text\Suggested by Matthias Daum\ -lemma int_power_div_base: - fixes k :: int - assumes "0 < m" "0 < k" - shows "k ^ m div k = (k::int) ^ (m - Suc 0)" -proof - - have eq: "k ^ m = k ^ ((m - Suc 0) + Suc 0)" - by (simp add: assms) - show ?thesis - using assms by (simp only: power_add eq) auto -qed - -text\Suggested by Matthias Daum\ -lemma int_div_less_self: - fixes x::int - assumes "0 < x" "1 < k" - shows "x div k < x" -proof - - have "nat x div nat k < nat x" - by (simp add: assms) - with assms show ?thesis - by (simp add: nat_div_distrib [symmetric]) -qed - -lemma mod_eq_dvd_iff_nat: - "m mod q = n mod q \ q dvd m - n" if "m \ n" for m n q :: nat -proof - - have "int m mod int q = int n mod int q \ int q dvd int m - int n" - by (simp add: mod_eq_dvd_iff) - with that have "int (m mod q) = int (n mod q) \ int q dvd int (m - n)" - by (simp only: of_nat_mod of_nat_diff) - then show ?thesis - by simp -qed - -lemma mod_eq_nat1E: - fixes m n q :: nat - assumes "m mod q = n mod q" and "m \ n" - obtains s where "m = n + q * s" -proof - - from assms have "q dvd m - n" - by (simp add: mod_eq_dvd_iff_nat) - then obtain s where "m - n = q * s" .. - with \m \ n\ have "m = n + q * s" - by simp - with that show thesis . -qed - -lemma mod_eq_nat2E: - fixes m n q :: nat - assumes "m mod q = n mod q" and "n \ m" - obtains s where "n = m + q * s" - using assms mod_eq_nat1E [of n q m] by (auto simp add: ac_simps) - -lemma nat_mod_eq_lemma: - assumes "(x::nat) mod n = y mod n" and "y \ x" - shows "\q. x = y + n * q" - using assms by (rule mod_eq_nat1E) (rule exI) - -lemma nat_mod_eq_iff: "(x::nat) mod n = y mod n \ (\q1 q2. x + n * q1 = y + n * q2)" - (is "?lhs = ?rhs") -proof - assume H: "x mod n = y mod n" - {assume xy: "x \ y" - from H have th: "y mod n = x mod n" by simp - from nat_mod_eq_lemma[OF th xy] have ?rhs - proof - fix q - assume "y = x + n * q" - then have "x + n * q = y + n * 0" - by simp - then show "\q1 q2. x + n * q1 = y + n * q2" - by blast - qed} - moreover - {assume xy: "y \ x" - from nat_mod_eq_lemma[OF H xy] have ?rhs - proof - fix q - assume "x = y + n * q" - then have "x + n * 0 = y + n * q" - by simp - then show "\q1 q2. x + n * q1 = y + n * q2" - by blast - qed} - ultimately show ?rhs using linear[of x y] by blast -next - assume ?rhs then obtain q1 q2 where q12: "x + n * q1 = y + n * q2" by blast - hence "(x + n * q1) mod n = (y + n * q2) mod n" by simp - thus ?lhs by simp -qed - - -subsubsection \Computing \div\ and \mod\ with shifting\ - -lemma div_pos_geq: - fixes k l :: int - assumes "0 < l" and "l \ k" - shows "k div l = (k - l) div l + 1" -proof - - have "k = (k - l) + l" by simp - then obtain j where k: "k = j + l" .. - with assms show ?thesis by (simp add: div_add_self2) -qed - -lemma mod_pos_geq: - fixes k l :: int - assumes "0 < l" and "l \ k" - shows "k mod l = (k - l) mod l" -proof - - have "k = (k - l) + l" by simp - then obtain j where k: "k = j + l" .. - with assms show ?thesis by simp -qed - -text\computing div by shifting\ - -lemma pos_zdiv_mult_2: \(1 + 2 * b) div (2 * a) = b div a\ (is ?Q) - and pos_zmod_mult_2: \(1 + 2 * b) mod (2 * a) = 1 + 2 * (b mod a)\ (is ?R) - if \0 \ a\ for a b :: int -proof - - have \((1 + 2 * b) div (2 * a), (1 + 2 * b) mod (2 * a)) = (b div a, 1 + 2 * (b mod a))\ - proof (cases \2 * a\ \b div a\ \1 + 2 * (b mod a)\ \1 + 2 * b\ rule: euclidean_relation_intI) - case by0 - then show ?case - by simp - next - case divides - have \even (2 * a)\ - by simp - then have \even (1 + 2 * b)\ - using \2 * a dvd 1 + 2 * b\ by (rule dvd_trans) - then show ?case - by simp - next - case euclidean_relation - with that have \a > 0\ - by simp - moreover have \b mod a < a\ - using \a > 0\ by simp - then have \1 + 2 * (b mod a) < 2 * a\ - by simp - moreover have \2 * (b mod a) + a * (2 * (b div a)) = 2 * (b div a * a + b mod a)\ - by (simp only: algebra_simps) - moreover have \0 \ 2 * (b mod a)\ - using \a > 0\ by simp - ultimately show ?case - by (simp add: algebra_simps) - qed - then show ?Q and ?R - by simp_all -qed - -lemma neg_zdiv_mult_2: \(1 + 2 * b) div (2 * a) = (b + 1) div a\ (is ?Q) - and neg_zmod_mult_2: \(1 + 2 * b) mod (2 * a) = 2 * ((b + 1) mod a) - 1\ (is ?R) - if \a \ 0\ for a b :: int -proof - - have \((1 + 2 * b) div (2 * a), (1 + 2 * b) mod (2 * a)) = ((b + 1) div a, 2 * ((b + 1) mod a) - 1)\ - proof (cases \2 * a\ \(b + 1) div a\ \2 * ((b + 1) mod a) - 1\ \1 + 2 * b\ rule: euclidean_relation_intI) - case by0 - then show ?case - by simp - next - case divides - have \even (2 * a)\ - by simp - then have \even (1 + 2 * b)\ - using \2 * a dvd 1 + 2 * b\ by (rule dvd_trans) - then show ?case - by simp - next - case euclidean_relation - with that have \a < 0\ - by simp - moreover have \(b + 1) mod a > a\ - using \a < 0\ by simp - then have \2 * ((b + 1) mod a) > 1 + 2 * a\ - by simp - moreover have \((1 + b) mod a) \ 0\ - using \a < 0\ by simp - then have \2 * ((1 + b) mod a) \ 0\ - by simp - moreover have \2 * ((1 + b) mod a) + a * (2 * ((1 + b) div a)) = - 2 * ((1 + b) div a * a + (1 + b) mod a)\ - by (simp only: algebra_simps) - ultimately show ?case - by (simp add: algebra_simps sgn_mult abs_mult) - qed - then show ?Q and ?R - by simp_all -qed - -lemma zdiv_numeral_Bit0 [simp]: - "numeral (Num.Bit0 v) div numeral (Num.Bit0 w) = - numeral v div (numeral w :: int)" - unfolding numeral.simps unfolding mult_2 [symmetric] - by (rule div_mult_mult1, simp) - -lemma zdiv_numeral_Bit1 [simp]: - "numeral (Num.Bit1 v) div numeral (Num.Bit0 w) = - (numeral v div (numeral w :: int))" - unfolding numeral.simps - unfolding mult_2 [symmetric] add.commute [of _ 1] - by (rule pos_zdiv_mult_2, simp) - -lemma zmod_numeral_Bit0 [simp]: - "numeral (Num.Bit0 v) mod numeral (Num.Bit0 w) = - (2::int) * (numeral v mod numeral w)" - unfolding numeral_Bit0 [of v] numeral_Bit0 [of w] - unfolding mult_2 [symmetric] by (rule mod_mult_mult1) - -lemma zmod_numeral_Bit1 [simp]: - "numeral (Num.Bit1 v) mod numeral (Num.Bit0 w) = - 2 * (numeral v mod numeral w) + (1::int)" - unfolding numeral_Bit1 [of v] numeral_Bit0 [of w] - unfolding mult_2 [symmetric] add.commute [of _ 1] - by (rule pos_zmod_mult_2, simp) - - -code_identifier - code_module Divides \ (SML) Arith and (OCaml) Arith and (Haskell) Arith - - -subsection \Lemmas of doubtful value\ - class unique_euclidean_semiring_numeral = unique_euclidean_semiring_with_nat + linordered_semidom + assumes div_less: "0 \ a \ a < b \ a div b = 0" and mod_less: " 0 \ a \ a < b \ a mod b = a" @@ -646,4 +121,7 @@ "k div l > 0" if "k \ l" and "l > 0" for k l :: int using that by (simp add: nonneg1_imp_zdiv_pos_iff) +code_identifier + code_module Divides \ (SML) Arith and (OCaml) Arith and (Haskell) Arith + end