# HG changeset patch # User haftmann # Date 1660888152 0 # Node ID 83e4b6a5e7de0b243e91f9392dd530ef77c784b5 # Parent 714fad33252e41c373ac486309cff7c8621dfcc4 streamlined theorems diff -r 714fad33252e -r 83e4b6a5e7de src/HOL/Divides.thy --- a/src/HOL/Divides.thy Fri Aug 19 05:49:11 2022 +0000 +++ b/src/HOL/Divides.thy Fri Aug 19 05:49:12 2022 +0000 @@ -11,112 +11,8 @@ subsection \More on division\ -subsubsection \Splitting Rules for div and mod\ - -text\The proofs of the two lemmas below are essentially identical\ - -lemma split_pos_lemma: - "0 - P(n div k :: int)(n mod k) = (\i j. 0\j \ j n = k*i + j \ P i j)" - by auto - -lemma split_neg_lemma: - "k<0 \ - P(n div k :: int)(n mod k) = (\i j. k j\0 \ n = k*i + j \ P i j)" - by auto - -lemma split_zdiv: - \P (n div k) \ - (k = 0 \ P 0) \ - (0 < k \ (\i j. 0 \ j \ j < k \ n = k * i + j \ P i)) \ - (k < 0 \ (\i j. k < j \ j \ 0 \ n = k * i + j \ P i))\ for n k :: int -proof (cases \k = 0\) - case True - then show ?thesis - by simp -next - case False - then have \k < 0 \ 0 < k\ - by auto - then show ?thesis - by (auto simp add: split_pos_lemma [of concl: "\x y. P x"] split_neg_lemma [of concl: "\x y. P x"]) -qed - -lemma split_zmod: - \P (n mod k) \ - (k = 0 \ P n) \ - (0 < k \ (\i j. 0 \ j \ j < k \ n = k * i + j \ P j)) \ - (k < 0 \ (\i j. k < j \ j \ 0 \ n = k * i + j \ P j))\ for n k :: int -proof (cases \k = 0\) - case True - then show ?thesis - by simp -next - case False - then have \k < 0 \ 0 < k\ - by auto - then show ?thesis - by (auto simp add: split_pos_lemma [of concl: "\x y. P y"] split_neg_lemma [of concl: "\x y. P y"]) -qed - -text \Enable (lin)arith to deal with \<^const>\divide\ and \<^const>\modulo\ - when these are applied to some constant that is of the form - \<^term>\numeral k\:\ -declare split_zdiv [of _ _ \numeral n\, linarith_split] for n -declare split_zdiv [of _ _ \- numeral n\, linarith_split] for n -declare split_zmod [of _ _ \numeral n\, linarith_split] for n -declare split_zmod [of _ _ \- numeral n\, linarith_split] for n - -lemma half_nonnegative_int_iff [simp]: - \k div 2 \ 0 \ k \ 0\ for k :: int - by auto - -lemma half_negative_int_iff [simp]: - \k div 2 < 0 \ k < 0\ for k :: int - by auto - -lemma zdiv_eq_0_iff: - "i div k = 0 \ k = 0 \ 0 \ i \ i < k \ i \ 0 \ k < i" (is "?L = ?R") - for i k :: int -proof - assume ?L - moreover have "?L \ ?R" - by (rule split_zdiv [THEN iffD2]) simp - ultimately show ?R - by blast -next - assume ?R then show ?L - by auto -qed - -lemma zmod_trivial_iff: - fixes i k :: int - shows "i mod k = i \ k = 0 \ 0 \ i \ i < k \ i \ 0 \ k < i" -proof - - have "i mod k = i \ i div k = 0" - using div_mult_mod_eq [of i k] by safe auto - with zdiv_eq_0_iff - show ?thesis - by simp -qed - - subsubsection \Monotonicity in the First Argument (Dividend)\ -inductive eucl_rel_int :: "int \ int \ int \ int \ bool" - where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)" - | eucl_rel_int_dividesI: "l \ 0 \ k = q * l \ eucl_rel_int k l (q, 0)" - | eucl_rel_int_remainderI: "sgn r = sgn l \ \r\ < \l\ - \ k = q * l + r \ eucl_rel_int k l (q, r)" - -lemma eucl_rel_int_iff: - "eucl_rel_int k l (q, r) \ - k = l * q + r \ - (if 0 < l then 0 \ r \ r < l else if l < 0 then l < r \ r \ 0 else q = 0)" - by (cases "r = 0") - (auto elim!: eucl_rel_int.cases intro: eucl_rel_int_by0 eucl_rel_int_dividesI eucl_rel_int_remainderI - simp add: ac_simps sgn_1_pos sgn_1_neg) - lemma unique_quotient_lemma: assumes "b * q' + r' \ b * q + r" "0 \ r'" "r' < b" "r < b" shows "q' \ (q::int)" proof - @@ -134,61 +30,6 @@ "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 unique_quotient: - "eucl_rel_int a b (q, r) \ eucl_rel_int a b (q', r') \ q = q'" - apply (rule order_antisym) - apply (simp_all add: eucl_rel_int_iff linorder_neq_iff split: if_split_asm) - apply (blast intro: order_eq_refl [THEN unique_quotient_lemma] order_eq_refl [THEN unique_quotient_lemma_neg] sym)+ - done - -lemma unique_remainder: - assumes "eucl_rel_int a b (q, r)" - and "eucl_rel_int a b (q', r')" - shows "r = r'" -proof - - have "q = q'" - using assms by (blast intro: unique_quotient) - then show "r = r'" - using assms by (simp add: eucl_rel_int_iff) -qed - -lemma eucl_rel_int: - "eucl_rel_int k l (k div l, k mod l)" -proof (cases k rule: int_cases3) - case zero - then show ?thesis - by (simp add: eucl_rel_int_iff divide_int_def modulo_int_def) -next - case (pos n) - then show ?thesis - using div_mult_mod_eq [of n] - by (cases l rule: int_cases3) - (auto simp del: of_nat_mult of_nat_add - simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps - eucl_rel_int_iff divide_int_def modulo_int_def) -next - case (neg n) - then show ?thesis - using div_mult_mod_eq [of n] - by (cases l rule: int_cases3) - (auto simp del: of_nat_mult of_nat_add - simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps - eucl_rel_int_iff divide_int_def modulo_int_def) -qed - -lemma divmod_int_unique: - assumes "eucl_rel_int k l (q, r)" - shows div_int_unique: "k div l = q" and mod_int_unique: "k mod l = r" - using assms eucl_rel_int [of k l] - using unique_quotient [of k l] unique_remainder [of k l] - by auto - -lemma zminus1_lemma: - "eucl_rel_int a b (q, r) ==> b \ 0 - ==> eucl_rel_int (-a) b (if r=0 then -q else -q - 1, - if r=0 then 0 else b-r)" -by (force simp add: eucl_rel_int_iff right_diff_distrib) - lemma zdiv_mono1: \a div b \ a' div b\ if \a \ a'\ \0 < b\ @@ -272,6 +113,72 @@ by simp qed (use assms in auto) + +subsubsection \Computing \div\ and \mod\ with shifting\ + +inductive eucl_rel_int :: "int \ int \ int \ int \ bool" + where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)" + | eucl_rel_int_dividesI: "l \ 0 \ k = q * l \ eucl_rel_int k l (q, 0)" + | eucl_rel_int_remainderI: "sgn r = sgn l \ \r\ < \l\ + \ k = q * l + r \ eucl_rel_int k l (q, r)" + +lemma eucl_rel_int_iff: + "eucl_rel_int k l (q, r) \ + k = l * q + r \ + (if 0 < l then 0 \ r \ r < l else if l < 0 then l < r \ r \ 0 else q = 0)" + by (cases "r = 0") + (auto elim!: eucl_rel_int.cases intro: eucl_rel_int_by0 eucl_rel_int_dividesI eucl_rel_int_remainderI + simp add: ac_simps sgn_1_pos sgn_1_neg) + +lemma unique_quotient: + "eucl_rel_int a b (q, r) \ eucl_rel_int a b (q', r') \ q = q'" + apply (rule order_antisym) + apply (simp_all add: eucl_rel_int_iff linorder_neq_iff split: if_split_asm) + apply (blast intro: order_eq_refl [THEN unique_quotient_lemma] order_eq_refl [THEN unique_quotient_lemma_neg] sym)+ + done + +lemma unique_remainder: + assumes "eucl_rel_int a b (q, r)" + and "eucl_rel_int a b (q', r')" + shows "r = r'" +proof - + have "q = q'" + using assms by (blast intro: unique_quotient) + then show "r = r'" + using assms by (simp add: eucl_rel_int_iff) +qed + +lemma eucl_rel_int: + "eucl_rel_int k l (k div l, k mod l)" +proof (cases k rule: int_cases3) + case zero + then show ?thesis + by (simp add: eucl_rel_int_iff divide_int_def modulo_int_def) +next + case (pos n) + then show ?thesis + using div_mult_mod_eq [of n] + by (cases l rule: int_cases3) + (auto simp del: of_nat_mult of_nat_add + simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps + eucl_rel_int_iff divide_int_def modulo_int_def) +next + case (neg n) + then show ?thesis + using div_mult_mod_eq [of n] + by (cases l rule: int_cases3) + (auto simp del: of_nat_mult of_nat_add + simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps + eucl_rel_int_iff divide_int_def modulo_int_def) +qed + +lemma divmod_int_unique: + assumes "eucl_rel_int k l (q, r)" + shows div_int_unique: "k div l = q" and mod_int_unique: "k mod l = r" + using assms eucl_rel_int [of k l] + using unique_quotient [of k l] unique_remainder [of k l] + by auto + lemma div_pos_geq: fixes k l :: int assumes "0 < l" and "l \ k" @@ -292,9 +199,6 @@ with assms show ?thesis by simp qed - -subsubsection \Computing \div\ and \mod\ with shifting\ - lemma pos_eucl_rel_int_mult_2: assumes "0 \ b" assumes "eucl_rel_int a b (q, r)" diff -r 714fad33252e -r 83e4b6a5e7de src/HOL/Euclidean_Division.thy --- a/src/HOL/Euclidean_Division.thy Fri Aug 19 05:49:11 2022 +0000 +++ b/src/HOL/Euclidean_Division.thy Fri Aug 19 05:49:12 2022 +0000 @@ -937,6 +937,14 @@ end +lemma div_nat_eqI: + "m div n = q" if "n * q \ m" and "m < n * Suc q" for m n q :: nat + by (rule div_eqI [of _ "m - n * q"]) (use that in \simp_all add: algebra_simps\) + +lemma mod_nat_eqI: + "m mod n = r" if "r < n" and "r \ m" and "n dvd m - r" for m n r :: nat + by (rule mod_eqI [of _ _ "(m - r) div n"]) (use that in \simp_all add: algebra_simps\) + text \Tool support\ ML \ @@ -967,14 +975,6 @@ simproc_setup cancel_div_mod_nat ("(m::nat) + n") = \K Cancel_Div_Mod_Nat.proc\ -lemma div_nat_eqI: - "m div n = q" if "n * q \ m" and "m < n * Suc q" for m n q :: nat - by (rule div_eqI [of _ "m - n * q"]) (use that in \simp_all add: algebra_simps\) - -lemma mod_nat_eqI: - "m mod n = r" if "r < n" and "r \ m" and "n dvd m - r" for m n r :: nat - by (rule mod_eqI [of _ _ "(m - r) div n"]) (use that in \simp_all add: algebra_simps\) - lemma div_mult_self_is_m [simp]: "m * n div n = m" if "n > 0" for m n :: nat using that by simp @@ -1030,6 +1030,41 @@ and mod_less [simp]: "m mod n = m" if "m < n" for m n :: nat using that by (auto intro: div_eqI mod_eqI) + +lemma split_div: + \P (m div n) \ + (n = 0 \ P 0) \ + (n \ 0 \ (\i j. j < n \ m = n * i + j \ P i))\ (is ?div) + and split_mod: + \Q (m mod n) \ + (n = 0 \ Q m) \ + (n \ 0 \ (\i j. j < n \ m = n * i + j \ Q j))\ (is ?mod) + for m n :: nat +proof - + have *: \R (m div n) (m mod n) \ + (n = 0 \ R 0 m) \ + (n \ 0 \ (\i j. j < n \ m = n * i + j \ R i j))\ for R + by (cases \n = 0\) auto + from * [of \\q _. P q\] show ?div . + from * [of \\_ r. Q r\] show ?mod . +qed + +declare split_div [of _ _ \numeral n\, linarith_split] for n +declare split_mod [of _ _ \numeral n\, linarith_split] for n + +lemma split_div': + "P (m div n) \ n = 0 \ P 0 \ (\q. (n * q \ m \ m < n * Suc q) \ P q)" +proof (cases "n = 0") + case True + then show ?thesis + by simp +next + case False + then have "n * q \ m \ m < n * Suc q \ m div n = q" for q + by (auto intro: div_nat_eqI dividend_less_times_div) + then show ?thesis + by auto +qed lemma le_div_geq: "m div n = Suc ((m - n) div n)" if "0 < n" and "n \ m" for m n :: nat @@ -1418,71 +1453,6 @@ by simp qed -lemma split_div: - "P (m div n) \ (n = 0 \ P 0) \ (n \ 0 \ - (\i j. j < n \ m = n * i + j \ P i))" - (is "?P = ?Q") for m n :: nat -proof (cases "n = 0") - case True - then show ?thesis - by simp -next - case False - show ?thesis - proof - assume ?P - with False show ?Q - by auto - next - assume ?Q - with False have *: "\i j. j < n \ m = n * i + j \ P i" - by simp - with False show ?P - by (auto intro: * [of "m mod n"]) - qed -qed - -lemma split_div': - "P (m div n) \ n = 0 \ P 0 \ (\q. (n * q \ m \ m < n * Suc q) \ P q)" -proof (cases "n = 0") - case True - then show ?thesis - by simp -next - case False - then have "n * q \ m \ m < n * Suc q \ m div n = q" for q - by (auto intro: div_nat_eqI dividend_less_times_div) - then show ?thesis - by auto -qed - -lemma split_mod: - "P (m mod n) \ (n = 0 \ P m) \ (n \ 0 \ - (\i j. j < n \ m = n * i + j \ P j))" - (is "?P \ ?Q") for m n :: nat -proof (cases "n = 0") - case True - then show ?thesis - by simp -next - case False - show ?thesis - proof - assume ?P - with False show ?Q - by auto - next - assume ?Q - with False have *: "\i j. j < n \ m = n * i + j \ P j" - by simp - with False show ?P - by (auto intro: * [of _ "m div n"]) - qed -qed - -declare split_div [of _ _ \numeral n\, linarith_split] for n -declare split_mod [of _ _ \numeral n\, linarith_split] for n - lemma funpow_mod_eq: \<^marker>\contributor \Lars Noschinski\\ \(f ^^ (m mod n)) x = (f ^^ m) x\ if \(f ^^ n) x = x\ proof - @@ -2192,6 +2162,64 @@ qed +subsubsection \Splitting Rules for div and mod\ + +lemma split_zdiv: + \P (n div k) \ + (k = 0 \ P 0) \ + (0 < k \ (\i j. 0 \ j \ j < k \ n = k * i + j \ P i)) \ + (k < 0 \ (\i j. k < j \ j \ 0 \ n = k * i + j \ P i))\ (is ?div) + and split_zmod: + \Q (n mod k) \ + (k = 0 \ Q n) \ + (0 < k \ (\i j. 0 \ j \ j < k \ n = k * i + j \ Q j)) \ + (k < 0 \ (\i j. k < j \ j \ 0 \ n = k * i + j \ Q j))\ (is ?mod) + for n k :: int +proof - + have *: \R (n div k) (n mod k) \ + (k = 0 \ R 0 n) \ + (0 < k \ (\i j. 0 \ j \ j < k \ n = k * i + j \ R i j)) \ + (k < 0 \ (\i j. k < j \ j \ 0 \ n = k * i + j \ R i j))\ for R + by (cases \k = 0\) + (auto simp add: linorder_class.neq_iff) + from * [of \\q _. P q\] show ?div . + from * [of \\_ r. Q r\] show ?mod . +qed + +text \Enable (lin)arith to deal with \<^const>\divide\ and \<^const>\modulo\ + when these are applied to some constant that is of the form + \<^term>\numeral k\:\ +declare split_zdiv [of _ _ \numeral n\, linarith_split] for n +declare split_zdiv [of _ _ \- numeral n\, linarith_split] for n +declare split_zmod [of _ _ \numeral n\, linarith_split] for n +declare split_zmod [of _ _ \- numeral n\, linarith_split] for n + +lemma zdiv_eq_0_iff: + "i div k = 0 \ k = 0 \ 0 \ i \ i < k \ i \ 0 \ k < i" (is "?L = ?R") + for i k :: int +proof + assume ?L + moreover have "?L \ ?R" + by (rule split_zdiv [THEN iffD2]) simp + ultimately show ?R + by blast +next + assume ?R then show ?L + by auto +qed + +lemma zmod_trivial_iff: + fixes i k :: int + shows "i mod k = i \ k = 0 \ 0 \ i \ i < k \ i \ 0 \ k < i" +proof - + have "i mod k = i \ i div k = 0" + using div_mult_mod_eq [of i k] by safe auto + with zdiv_eq_0_iff + show ?thesis + by simp +qed + + subsubsection \Algebraic rewrites\ lemma zdiv_zmult2_eq: @@ -2230,6 +2258,14 @@ using mod_mult2_eq' [of \- a\ \nat (- b)\ \nat c\] by simp qed +lemma half_nonnegative_int_iff [simp]: + \k div 2 \ 0 \ k \ 0\ for k :: int + by auto + +lemma half_negative_int_iff [simp]: + \k div 2 < 0 \ k < 0\ for k :: int + by auto + subsubsection \Distributive laws for conversions.\