# HG changeset patch # User haftmann # Date 1507494501 -7200 # Node ID 1907167b60383c049804ec3b7f8069b4142a8990 # Parent c3631f32dfeb81f1bcd5eccefde5d17116583c9f elementary definition of division on natural numbers diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Computational_Algebra/Polynomial_Factorial.thy --- a/src/HOL/Computational_Algebra/Polynomial_Factorial.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Computational_Algebra/Polynomial_Factorial.thy Sun Oct 08 22:28:21 2017 +0200 @@ -15,7 +15,7 @@ definition to_fract :: "'a :: idom \ 'a fract" where "to_fract x = Fract x 1" - \ \FIXME: name \of_idom\, abbreviation\ + \ \FIXME: more idiomatic name, abbreviation\ lemma to_fract_0 [simp]: "to_fract 0 = 0" by (simp add: to_fract_def eq_fract Zero_fract_def) @@ -438,8 +438,8 @@ by (simp add: irreducible_dict) show "comm_semiring_1.prime_elem times 1 0 = prime_elem" by (simp add: prime_elem_dict) - show "class.unique_euclidean_ring divide plus minus (0 :: 'a poly) times 1 modulo - (\p. [:lead_coeff p:]) (\p. smult (inverse (lead_coeff p)) p) + show "class.unique_euclidean_ring divide plus minus (0 :: 'a poly) times 1 + (\p. [:lead_coeff p:]) (\p. smult (inverse (lead_coeff p)) p) modulo (\p. if p = 0 then 0 else 2 ^ degree p) uminus top" proof (standard, fold dvd_dict) fix p :: "'a poly" diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Divides.thy --- a/src/HOL/Divides.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Divides.thy Sun Oct 08 22:28:21 2017 +0200 @@ -9,95 +9,6 @@ imports Parity begin -subsection \Parity\ - -class unique_euclidean_semiring_parity = unique_euclidean_semiring + - assumes parity: "a mod 2 = 0 \ a mod 2 = 1" - assumes one_mod_two_eq_one [simp]: "1 mod 2 = 1" - assumes zero_not_eq_two: "0 \ 2" -begin - -lemma parity_cases [case_names even odd]: - assumes "a mod 2 = 0 \ P" - assumes "a mod 2 = 1 \ P" - shows P - using assms parity by blast - -lemma one_div_two_eq_zero [simp]: - "1 div 2 = 0" -proof (cases "2 = 0") - case True then show ?thesis by simp -next - case False - from div_mult_mod_eq have "1 div 2 * 2 + 1 mod 2 = 1" . - with one_mod_two_eq_one have "1 div 2 * 2 + 1 = 1" by simp - then have "1 div 2 * 2 = 0" by (simp add: ac_simps add_left_imp_eq del: mult_eq_0_iff) - then have "1 div 2 = 0 \ 2 = 0" by simp - with False show ?thesis by auto -qed - -lemma not_mod_2_eq_0_eq_1 [simp]: - "a mod 2 \ 0 \ a mod 2 = 1" - by (cases a rule: parity_cases) simp_all - -lemma not_mod_2_eq_1_eq_0 [simp]: - "a mod 2 \ 1 \ a mod 2 = 0" - by (cases a rule: parity_cases) simp_all - -subclass semiring_parity -proof (unfold_locales, unfold dvd_eq_mod_eq_0 not_mod_2_eq_0_eq_1) - show "1 mod 2 = 1" - by (fact one_mod_two_eq_one) -next - fix a b - assume "a mod 2 = 1" - moreover assume "b mod 2 = 1" - ultimately show "(a + b) mod 2 = 0" - using mod_add_eq [of a 2 b] by simp -next - fix a b - assume "(a * b) mod 2 = 0" - then have "(a mod 2) * (b mod 2) mod 2 = 0" - by (simp add: mod_mult_eq) - then have "(a mod 2) * (b mod 2) = 0" - by (cases "a mod 2 = 0") simp_all - then show "a mod 2 = 0 \ b mod 2 = 0" - by (rule divisors_zero) -next - fix a - assume "a mod 2 = 1" - then have "a = a div 2 * 2 + 1" - using div_mult_mod_eq [of a 2] by simp - then show "\b. a = b + 1" .. -qed - -lemma even_iff_mod_2_eq_zero: - "even a \ a mod 2 = 0" - by (fact dvd_eq_mod_eq_0) - -lemma odd_iff_mod_2_eq_one: - "odd a \ a mod 2 = 1" - by (simp add: even_iff_mod_2_eq_zero) - -lemma even_succ_div_two [simp]: - "even a \ (a + 1) div 2 = a div 2" - by (cases "a = 0") (auto elim!: evenE dest: mult_not_zero) - -lemma odd_succ_div_two [simp]: - "odd a \ (a + 1) div 2 = a div 2 + 1" - by (auto elim!: oddE simp add: zero_not_eq_two [symmetric] add.assoc) - -lemma even_two_times_div_two: - "even a \ 2 * (a div 2) = a" - by (fact dvd_mult_div_cancel) - -lemma odd_two_times_div_two_succ [simp]: - "odd a \ 2 * (a div 2) + 1 = a" - using mult_div_mod_eq [of 2 a] by (simp add: even_iff_mod_2_eq_zero) - -end - - subsection \Numeral division with a pragmatic type class\ text \ @@ -382,445 +293,11 @@ end +hide_fact (open) div_less mod_less mod_less_eq_dividend mod_mult2_eq div_mult2_eq + subsection \Division on @{typ nat}\ -context -begin - -text \ - We define @{const divide} and @{const modulo} on @{typ nat} by means - of a characteristic relation with two input arguments - @{term "m::nat"}, @{term "n::nat"} and two output arguments - @{term "q::nat"}(uotient) and @{term "r::nat"}(emainder). -\ - -inductive eucl_rel_nat :: "nat \ nat \ nat \ nat \ bool" - where eucl_rel_nat_by0: "eucl_rel_nat m 0 (0, m)" - | eucl_rel_natI: "r < n \ m = q * n + r \ eucl_rel_nat m n (q, r)" - -text \@{const eucl_rel_nat} is total:\ - -qualified lemma eucl_rel_nat_ex: - obtains q r where "eucl_rel_nat m n (q, r)" -proof (cases "n = 0") - case True - with that eucl_rel_nat_by0 show thesis - by blast -next - case False - have "\q r. m = q * n + r \ r < n" - proof (induct m) - case 0 with \n \ 0\ - have "(0::nat) = 0 * n + 0 \ 0 < n" by simp - then show ?case by blast - next - case (Suc m) then obtain q' r' - where m: "m = q' * n + r'" and n: "r' < n" by auto - then show ?case proof (cases "Suc r' < n") - case True - from m n have "Suc m = q' * n + Suc r'" by simp - with True show ?thesis by blast - next - case False then have "n \ Suc r'" - by (simp add: not_less) - moreover from n have "Suc r' \ n" - by (simp add: Suc_le_eq) - ultimately have "n = Suc r'" by auto - with m have "Suc m = Suc q' * n + 0" by simp - with \n \ 0\ show ?thesis by blast - qed - qed - with that \n \ 0\ eucl_rel_natI show thesis - by blast -qed - -text \@{const eucl_rel_nat} is injective:\ - -qualified lemma eucl_rel_nat_unique_div: - assumes "eucl_rel_nat m n (q, r)" - and "eucl_rel_nat m n (q', r')" - shows "q = q'" -proof (cases "n = 0") - case True with assms show ?thesis - by (auto elim: eucl_rel_nat.cases) -next - case False - have *: "q' \ q" if "q' * n + r' = q * n + r" "r < n" for q r q' r' :: nat - proof (rule ccontr) - assume "\ q' \ q" - then have "q < q'" - by (simp add: not_le) - with that show False - by (auto simp add: less_iff_Suc_add algebra_simps) - qed - from \n \ 0\ assms show ?thesis - by (auto intro: order_antisym elim: eucl_rel_nat.cases dest: * sym split: if_splits) -qed - -qualified lemma eucl_rel_nat_unique_mod: - assumes "eucl_rel_nat m n (q, r)" - and "eucl_rel_nat m n (q', r')" - shows "r = r'" -proof - - from assms have "q' = q" - by (auto intro: eucl_rel_nat_unique_div) - with assms show ?thesis - by (auto elim!: eucl_rel_nat.cases) -qed - -text \ - We instantiate divisibility on the natural numbers by - means of @{const eucl_rel_nat}: -\ - -qualified definition divmod_nat :: "nat \ nat \ nat \ nat" where - "divmod_nat m n = (THE qr. eucl_rel_nat m n qr)" - -qualified lemma eucl_rel_nat_divmod_nat: - "eucl_rel_nat m n (divmod_nat m n)" -proof - - from eucl_rel_nat_ex - obtain q r where rel: "eucl_rel_nat m n (q, r)" . - then show ?thesis - by (auto simp add: divmod_nat_def intro: theI - elim: eucl_rel_nat_unique_div eucl_rel_nat_unique_mod) -qed - -qualified lemma divmod_nat_unique: - "divmod_nat m n = (q, r)" if "eucl_rel_nat m n (q, r)" - using that - by (auto simp add: divmod_nat_def intro: eucl_rel_nat_divmod_nat elim: eucl_rel_nat_unique_div eucl_rel_nat_unique_mod) - -qualified lemma divmod_nat_zero: - "divmod_nat m 0 = (0, m)" - by (rule divmod_nat_unique) (fact eucl_rel_nat_by0) - -qualified lemma divmod_nat_zero_left: - "divmod_nat 0 n = (0, 0)" - by (rule divmod_nat_unique) - (cases n, auto intro: eucl_rel_nat_by0 eucl_rel_natI) - -qualified lemma divmod_nat_base: - "m < n \ divmod_nat m n = (0, m)" - by (rule divmod_nat_unique) - (cases n, auto intro: eucl_rel_nat_by0 eucl_rel_natI) - -qualified lemma divmod_nat_step: - assumes "0 < n" and "n \ m" - shows "divmod_nat m n = - (Suc (fst (divmod_nat (m - n) n)), snd (divmod_nat (m - n) n))" -proof (rule divmod_nat_unique) - have "eucl_rel_nat (m - n) n (divmod_nat (m - n) n)" - by (fact eucl_rel_nat_divmod_nat) - then show "eucl_rel_nat m n (Suc - (fst (divmod_nat (m - n) n)), snd (divmod_nat (m - n) n))" - using assms - by (auto split: if_splits intro: eucl_rel_natI elim!: eucl_rel_nat.cases simp add: algebra_simps) -qed - -end - -instantiation nat :: "{semidom_modulo, normalization_semidom}" -begin - -definition normalize_nat :: "nat \ nat" - where [simp]: "normalize = (id :: nat \ nat)" - -definition unit_factor_nat :: "nat \ nat" - where "unit_factor n = (if n = 0 then 0 else 1 :: nat)" - -lemma unit_factor_simps [simp]: - "unit_factor 0 = (0::nat)" - "unit_factor (Suc n) = 1" - by (simp_all add: unit_factor_nat_def) - -definition divide_nat :: "nat \ nat \ nat" - where div_nat_def: "m div n = fst (Divides.divmod_nat m n)" - -definition modulo_nat :: "nat \ nat \ nat" - where mod_nat_def: "m mod n = snd (Divides.divmod_nat m n)" - -lemma fst_divmod_nat [simp]: - "fst (Divides.divmod_nat m n) = m div n" - by (simp add: div_nat_def) - -lemma snd_divmod_nat [simp]: - "snd (Divides.divmod_nat m n) = m mod n" - by (simp add: mod_nat_def) - -lemma divmod_nat_div_mod: - "Divides.divmod_nat m n = (m div n, m mod n)" - by (simp add: prod_eq_iff) - -lemma div_nat_unique: - assumes "eucl_rel_nat m n (q, r)" - shows "m div n = q" - using assms - by (auto dest!: Divides.divmod_nat_unique simp add: prod_eq_iff) - -lemma mod_nat_unique: - assumes "eucl_rel_nat m n (q, r)" - shows "m mod n = r" - using assms - by (auto dest!: Divides.divmod_nat_unique simp add: prod_eq_iff) - -lemma eucl_rel_nat: "eucl_rel_nat m n (m div n, m mod n)" - using Divides.eucl_rel_nat_divmod_nat - by (simp add: divmod_nat_div_mod) - -text \The ''recursion'' equations for @{const divide} and @{const modulo}\ - -lemma div_less [simp]: - fixes m n :: nat - assumes "m < n" - shows "m div n = 0" - using assms Divides.divmod_nat_base by (simp add: prod_eq_iff) - -lemma le_div_geq: - fixes m n :: nat - assumes "0 < n" and "n \ m" - shows "m div n = Suc ((m - n) div n)" - using assms Divides.divmod_nat_step by (simp add: prod_eq_iff) - -lemma mod_less [simp]: - fixes m n :: nat - assumes "m < n" - shows "m mod n = m" - using assms Divides.divmod_nat_base by (simp add: prod_eq_iff) - -lemma le_mod_geq: - fixes m n :: nat - assumes "n \ m" - shows "m mod n = (m - n) mod n" - using assms Divides.divmod_nat_step by (cases "n = 0") (simp_all add: prod_eq_iff) - -lemma mod_less_divisor [simp]: - fixes m n :: nat - assumes "n > 0" - shows "m mod n < n" - using assms eucl_rel_nat [of m n] - by (auto elim: eucl_rel_nat.cases) - -lemma mod_le_divisor [simp]: - fixes m n :: nat - assumes "n > 0" - shows "m mod n \ n" - using assms eucl_rel_nat [of m n] - by (auto elim: eucl_rel_nat.cases) - -instance proof - fix m n :: nat - show "m div n * n + m mod n = m" - using eucl_rel_nat [of m n] - by (auto elim: eucl_rel_nat.cases) -next - fix n :: nat show "n div 0 = 0" - by (simp add: div_nat_def Divides.divmod_nat_zero) -next - fix m n :: nat - assume "n \ 0" - then show "m * n div n = m" - by (auto intro!: eucl_rel_natI div_nat_unique [of _ _ _ 0]) -qed (simp_all add: unit_factor_nat_def) - -end - -text \Simproc for cancelling @{const divide} and @{const modulo}\ - -lemma (in semiring_modulo) cancel_div_mod_rules: - "((a div b) * b + a mod b) + c = a + c" - "(b * (a div b) + a mod b) + c = a + c" - by (simp_all add: div_mult_mod_eq mult_div_mod_eq) - -ML_file "~~/src/Provers/Arith/cancel_div_mod.ML" - -ML \ -structure Cancel_Div_Mod_Nat = Cancel_Div_Mod -( - val div_name = @{const_name divide}; - val mod_name = @{const_name modulo}; - val mk_binop = HOLogic.mk_binop; - val mk_plus = HOLogic.mk_binop @{const_name Groups.plus}; - val dest_plus = HOLogic.dest_bin @{const_name Groups.plus} HOLogic.natT; - fun mk_sum [] = HOLogic.zero - | mk_sum [t] = t - | mk_sum (t :: ts) = mk_plus (t, mk_sum ts); - fun dest_sum tm = - if HOLogic.is_zero tm then [] - else - (case try HOLogic.dest_Suc tm of - SOME t => HOLogic.Suc_zero :: dest_sum t - | NONE => - (case try dest_plus tm of - SOME (t, u) => dest_sum t @ dest_sum u - | NONE => [tm])); - - val div_mod_eqs = map mk_meta_eq @{thms cancel_div_mod_rules}; - - val prove_eq_sums = Arith_Data.prove_conv2 all_tac - (Arith_Data.simp_all_tac @{thms add_0_left add_0_right ac_simps}) -) -\ - -simproc_setup cancel_div_mod_nat ("(m::nat) + n") = - \K Cancel_Div_Mod_Nat.proc\ - -lemma div_by_Suc_0 [simp]: - "m div Suc 0 = m" - using div_by_1 [of m] by simp - -lemma mod_by_Suc_0 [simp]: - "m mod Suc 0 = 0" - using mod_by_1 [of m] by simp - -lemma mod_greater_zero_iff_not_dvd: - fixes m n :: nat - shows "m mod n > 0 \ \ n dvd m" - by (simp add: dvd_eq_mod_eq_0) - -instantiation nat :: unique_euclidean_semiring -begin - -definition [simp]: - "euclidean_size_nat = (id :: nat \ nat)" - -definition [simp]: - "uniqueness_constraint_nat = (top :: nat \ nat \ bool)" - -instance proof - fix n q r :: nat - assume "euclidean_size r < euclidean_size n" - then have "n > r" - by simp_all - then have "eucl_rel_nat (q * n + r) n (q, r)" - by (rule eucl_rel_natI) rule - then show "(q * n + r) div n = q" - by (rule div_nat_unique) -qed (use mult_le_mono2 [of 1] in \simp_all\) - -end - -lemma divmod_nat_if [code]: - "Divides.divmod_nat m n = (if n = 0 \ m < n then (0, m) else - let (q, r) = Divides.divmod_nat (m - n) n in (Suc q, r))" - by (simp add: prod_eq_iff case_prod_beta not_less le_div_geq le_mod_geq) - -lemma mod_Suc_eq [mod_simps]: - "Suc (m mod n) mod n = Suc m mod n" -proof - - have "(m mod n + 1) mod n = (m + 1) mod n" - by (simp only: mod_simps) - then show ?thesis - by simp -qed - -lemma mod_Suc_Suc_eq [mod_simps]: - "Suc (Suc (m mod n)) mod n = Suc (Suc m) mod n" -proof - - have "(m mod n + 2) mod n = (m + 2) mod n" - by (simp only: mod_simps) - then show ?thesis - by simp -qed - - -subsubsection \Quotient\ - -lemma div_geq: "0 < n \ \ m < n \ m div n = Suc ((m - n) div n)" -by (simp add: le_div_geq linorder_not_less) - -lemma div_if: "0 < n \ m div n = (if m < n then 0 else Suc ((m - n) div n))" -by (simp add: div_geq) - -lemma div_mult_self_is_m [simp]: "0 (m*n) div n = (m::nat)" -by simp - -lemma div_mult_self1_is_m [simp]: "0 (n*m) div n = (m::nat)" -by simp - -lemma div_positive: - fixes m n :: nat - assumes "n > 0" - assumes "m \ n" - shows "m div n > 0" -proof - - from \m \ n\ obtain q where "m = n + q" - by (auto simp add: le_iff_add) - with \n > 0\ show ?thesis by (simp add: div_add_self1) -qed - -lemma div_eq_0_iff: "(a div b::nat) = 0 \ a < b \ b = 0" - by auto (metis div_positive less_numeral_extra(3) not_less) - - -subsubsection \Remainder\ - -lemma mod_Suc_le_divisor [simp]: - "m mod Suc n \ n" - using mod_less_divisor [of "Suc n" m] by arith - -lemma mod_less_eq_dividend [simp]: - fixes m n :: nat - shows "m mod n \ m" -proof (rule add_leD2) - from div_mult_mod_eq have "m div n * n + m mod n = m" . - then show "m div n * n + m mod n \ m" by auto -qed - -lemma mod_geq: "\ m < (n::nat) \ m mod n = (m - n) mod n" -by (simp add: le_mod_geq linorder_not_less) - -lemma mod_if: "m mod (n::nat) = (if m < n then m else (m - n) mod n)" -by (simp add: le_mod_geq) - - -subsubsection \Quotient and Remainder\ - -lemma div_mult1_eq: - "(a * b) div c = a * (b div c) + a * (b mod c) div (c::nat)" - by (cases "c = 0") - (auto simp add: algebra_simps distrib_left [symmetric] - intro!: div_nat_unique [of _ _ _ "(a * (b mod c)) mod c"] eucl_rel_natI) - -lemma eucl_rel_nat_add1_eq: - "eucl_rel_nat a c (aq, ar) \ eucl_rel_nat b c (bq, br) - \ eucl_rel_nat (a + b) c (aq + bq + (ar + br) div c, (ar + br) mod c)" - by (auto simp add: split_ifs algebra_simps elim!: eucl_rel_nat.cases intro: eucl_rel_nat_by0 eucl_rel_natI) - -(*NOT suitable for rewriting: the RHS has an instance of the LHS*) -lemma div_add1_eq: - "(a + b) div (c::nat) = a div c + b div c + ((a mod c + b mod c) div c)" -by (blast intro: eucl_rel_nat_add1_eq [THEN div_nat_unique] eucl_rel_nat) - -lemma eucl_rel_nat_mult2_eq: - assumes "eucl_rel_nat a b (q, r)" - shows "eucl_rel_nat a (b * c) (q div c, b *(q mod c) + r)" -proof (cases "c = 0") - case True - with assms show ?thesis - by (auto intro: eucl_rel_nat_by0 elim!: eucl_rel_nat.cases simp add: ac_simps) -next - case False - { assume "r < b" - with False have "b * (q mod c) + r < b * c" - apply (cut_tac m = q and n = c in mod_less_divisor) - apply (drule_tac [2] m = "q mod c" in less_imp_Suc_add, auto) - apply (erule_tac P = "%x. lhs < rhs x" for lhs rhs in ssubst) - apply (simp add: add_mult_distrib2) - done - then have "r + b * (q mod c) < b * c" - by (simp add: ac_simps) - } with assms False show ?thesis - by (auto simp add: algebra_simps add_mult_distrib2 [symmetric] elim!: eucl_rel_nat.cases intro: eucl_rel_nat.intros) -qed - -lemma div_mult2_eq: "a div (b * c) = (a div b) div (c::nat)" -by (force simp add: eucl_rel_nat [THEN eucl_rel_nat_mult2_eq, THEN div_nat_unique]) - -lemma mod_mult2_eq: "a mod (b * c) = b * (a div b mod c) + a mod (b::nat)" -by (auto simp add: mult.commute eucl_rel_nat [THEN eucl_rel_nat_mult2_eq, THEN mod_nat_unique]) - instantiation nat :: unique_euclidean_semiring_numeral begin @@ -834,370 +311,15 @@ in if r \ numeral l then (2 * q + 1, r - numeral l) else (2 * q, r))" -instance - by standard (auto intro: div_positive simp add: divmod'_nat_def divmod_step_nat_def mod_mult2_eq div_mult2_eq) +instance by standard + (auto simp add: divmod'_nat_def divmod_step_nat_def div_greater_zero_iff div_mult2_eq mod_mult2_eq) end declare divmod_algorithm_code [where ?'a = nat, code] - -subsubsection \Further Facts about Quotient and Remainder\ - -lemma div_le_mono: - fixes m n k :: nat - assumes "m \ n" - shows "m div k \ n div k" -proof - - from assms obtain q where "n = m + q" - by (auto simp add: le_iff_add) - then show ?thesis - by (simp add: div_add1_eq [of m q k]) -qed - -(* Antimonotonicity of div in second argument *) -lemma div_le_mono2: "!!m::nat. [| 0n |] ==> (k div n) \ (k div m)" -apply (subgoal_tac "0 (k-m) div n") - prefer 2 - apply (blast intro: div_le_mono diff_le_mono2) -apply (rule le_trans, simp) -apply (simp) -done - -lemma div_le_dividend [simp]: "m div n \ (m::nat)" -apply (case_tac "n=0", simp) -apply (subgoal_tac "m div n \ m div 1", simp) -apply (rule div_le_mono2) -apply (simp_all (no_asm_simp)) -done - -(* Similar for "less than" *) -lemma div_less_dividend [simp]: - "\(1::nat) < n; 0 < m\ \ m div n < m" -apply (induct m rule: nat_less_induct) -apply (rename_tac "m") -apply (case_tac "mA fact for the mutilated chess board\ -lemma mod_Suc: "Suc(m) mod n = (if Suc(m mod n) = n then 0 else Suc(m mod n))" -apply (case_tac "n=0", simp) -apply (induct "m" rule: nat_less_induct) -apply (case_tac "Suc (na) Suc(na) *) -apply (simp add: linorder_not_less le_Suc_eq mod_geq) -apply (auto simp add: Suc_diff_le le_mod_geq) -done - -lemma mod_eq_0_iff: "(m mod d = 0) = (\q::nat. m = d*q)" -by (auto simp add: dvd_eq_mod_eq_0 [symmetric] dvd_def) - -lemmas mod_eq_0D [dest!] = mod_eq_0_iff [THEN iffD1] - -(*Loses information, namely we also have rq. m = r + q * d" -proof - - from div_mult_mod_eq obtain q where "q * d + m mod d = m" by blast - with assms have "m = r + q * d" by simp - then show ?thesis .. -qed - -lemma split_div: - "P(n div k :: nat) = - ((k = 0 \ P 0) \ (k \ 0 \ (!i. !j P i)))" - (is "?P = ?Q" is "_ = (_ \ (_ \ ?R))") -proof - assume P: ?P - show ?Q - proof (cases) - assume "k = 0" - with P show ?Q by simp - next - assume not0: "k \ 0" - thus ?Q - proof (simp, intro allI impI) - fix i j - assume n: "n = k*i + j" and j: "j < k" - show "P i" - proof (cases) - assume "i = 0" - with n j P show "P i" by simp - next - assume "i \ 0" - with not0 n j P show "P i" by(simp add:ac_simps) - qed - qed - qed -next - assume Q: ?Q - show ?P - proof (cases) - assume "k = 0" - with Q show ?P by simp - next - assume not0: "k \ 0" - with Q have R: ?R by simp - from not0 R[THEN spec,of "n div k",THEN spec, of "n mod k"] - show ?P by simp - qed -qed - -lemma split_div_lemma: - assumes "0 < n" - shows "n * q \ m \ m < n * Suc q \ q = ((m::nat) div n)" (is "?lhs \ ?rhs") -proof - assume ?rhs - with minus_mod_eq_mult_div [symmetric] have nq: "n * q = m - (m mod n)" by simp - then have A: "n * q \ m" by simp - have "n - (m mod n) > 0" using mod_less_divisor assms by auto - then have "m < m + (n - (m mod n))" by simp - then have "m < n + (m - (m mod n))" by simp - with nq have "m < n + n * q" by simp - then have B: "m < n * Suc q" by simp - from A B show ?lhs .. -next - assume P: ?lhs - then have "eucl_rel_nat m n (q, m - n * q)" - by (auto intro: eucl_rel_natI simp add: ac_simps) - then have "m div n = q" - by (rule div_nat_unique) - then show ?rhs by simp -qed - -theorem split_div': - "P ((m::nat) div n) = ((n = 0 \ P 0) \ - (\q. (n * q \ m \ m < n * (Suc q)) \ P q))" - apply (cases "0 < n") - apply (simp only: add: split_div_lemma) - apply simp_all - done - -lemma split_mod: - "P(n mod k :: nat) = - ((k = 0 \ P n) \ (k \ 0 \ (!i. !j P j)))" - (is "?P = ?Q" is "_ = (_ \ (_ \ ?R))") -proof - assume P: ?P - show ?Q - proof (cases) - assume "k = 0" - with P show ?Q by simp - next - assume not0: "k \ 0" - thus ?Q - proof (simp, intro allI impI) - fix i j - assume "n = k*i + j" "j < k" - thus "P j" using not0 P by (simp add: ac_simps) - qed - qed -next - assume Q: ?Q - show ?P - proof (cases) - assume "k = 0" - with Q show ?P by simp - next - assume not0: "k \ 0" - with Q have R: ?R by simp - from not0 R[THEN spec,of "n div k",THEN spec, of "n mod k"] - show ?P by simp - qed -qed - -lemma div_eq_dividend_iff: "a \ 0 \ (a :: nat) div b = a \ b = 1" - apply rule - apply (cases "b = 0") - apply simp_all - apply (metis (full_types) One_nat_def Suc_lessI div_less_dividend less_not_refl3) - done - -lemma (in field_char_0) of_nat_div: - "of_nat (m div n) = ((of_nat m - of_nat (m mod n)) / of_nat n)" -proof - - have "of_nat (m div n) = ((of_nat (m div n * n + m mod n) - of_nat (m mod n)) / of_nat n :: 'a)" - unfolding of_nat_add by (cases "n = 0") simp_all - then show ?thesis - by simp -qed - - -subsubsection \An ``induction'' law for modulus arithmetic.\ - -lemma mod_induct_0: - assumes step: "\i P ((Suc i) mod p)" - and base: "P i" and i: "i(P 0)" - from i have p: "0k. 0 \ P (p-k)" (is "\k. ?A k") - proof - fix k - show "?A k" - proof (induct k) - show "?A 0" by simp \ "by contradiction" - next - fix n - assume ih: "?A n" - show "?A (Suc n)" - proof (clarsimp) - assume y: "P (p - Suc n)" - have n: "Suc n < p" - proof (rule ccontr) - assume "\(Suc n < p)" - hence "p - Suc n = 0" - by simp - with y contra show "False" - by simp - qed - hence n2: "Suc (p - Suc n) = p-n" by arith - from p have "p - Suc n < p" by arith - with y step have z: "P ((Suc (p - Suc n)) mod p)" - by blast - show "False" - proof (cases "n=0") - case True - with z n2 contra show ?thesis by simp - next - case False - with p have "p-n < p" by arith - with z n2 False ih show ?thesis by simp - qed - qed - qed - qed - moreover - from i obtain k where "0 i+k=p" - by (blast dest: less_imp_add_positive) - hence "0 i=p-k" by auto - moreover - note base - ultimately - show "False" by blast -qed - -lemma mod_induct: - assumes step: "\i P ((Suc i) mod p)" - and base: "P i" and i: "ij P j" (is "?A j") - proof (induct j) - from step base i show "?A 0" - by (auto elim: mod_induct_0) - next - fix k - assume ih: "?A k" - show "?A (Suc k)" - proof - assume suc: "Suc k < p" - hence k: "k m mod 2 = 1" -proof - - { fix n :: nat have "(n::nat) < 2 \ n = 0 \ n = 1" by (cases n) simp_all } - moreover have "m mod 2 < 2" by simp - ultimately have "m mod 2 = 0 \ m mod 2 = 1" . - then show ?thesis by auto -qed - -text\These lemmas collapse some needless occurrences of Suc: - at least three Sucs, since two and fewer are rewritten back to Suc again! - We already have some rules to simplify operands smaller than 3.\ - -lemma div_Suc_eq_div_add3 [simp]: "m div (Suc (Suc (Suc n))) = m div (3+n)" -by (simp add: Suc3_eq_add_3) - -lemma mod_Suc_eq_mod_add3 [simp]: "m mod (Suc (Suc (Suc n))) = m mod (3+n)" -by (simp add: Suc3_eq_add_3) - -lemma Suc_div_eq_add3_div: "(Suc (Suc (Suc m))) div n = (3+m) div n" -by (simp add: Suc3_eq_add_3) - -lemma Suc_mod_eq_add3_mod: "(Suc (Suc (Suc m))) mod n = (3+m) mod n" -by (simp add: Suc3_eq_add_3) - -lemmas Suc_div_eq_add3_div_numeral [simp] = Suc_div_eq_add3_div [of _ "numeral v"] for v -lemmas Suc_mod_eq_add3_mod_numeral [simp] = Suc_mod_eq_add3_mod [of _ "numeral v"] for v - -lemma Suc_times_mod_eq: "1 Suc (k * m) mod k = 1" -apply (induct "m") -apply (simp_all add: mod_Suc) -done - -declare Suc_times_mod_eq [of "numeral w", simp] for w - -lemma Suc_div_le_mono [simp]: "n div k \ (Suc n) div k" -by (simp add: div_le_mono) - -lemma Suc_n_div_2_gt_zero [simp]: "(0::nat) < n ==> 0 < (n + 1) div 2" -by (cases n) simp_all - -lemma div_2_gt_zero [simp]: assumes A: "(1::nat) < n" shows "0 < n div 2" -proof - - from A have B: "0 < n - 1" and C: "n - 1 + 1 = n" by simp_all - from Suc_n_div_2_gt_zero [OF B] C show ?thesis by simp -qed - -lemma mod_mult_self3' [simp]: "Suc (k * n + m) mod n = Suc m mod n" - using mod_mult_self3 [of k n "Suc m"] by simp - -lemma mod_Suc_eq_Suc_mod: "Suc m mod n = Suc (m mod n) mod n" -apply (subst mod_Suc [of m]) -apply (subst mod_Suc [of "m mod n"], simp) -done - -lemma mod_2_not_eq_zero_eq_one_nat: - fixes n :: nat - shows "n mod 2 \ 0 \ n mod 2 = 1" - by (fact not_mod_2_eq_0_eq_1) +lemma odd_Suc_minus_one [simp]: "odd n \ Suc (n - Suc 0) = n" + by (auto elim: oddE) lemma even_Suc_div_two [simp]: "even n \ Suc n div 2 = n div 2" @@ -1245,6 +367,11 @@ qed qed +lemma mod_2_not_eq_zero_eq_one_nat: + fixes n :: nat + shows "n mod 2 \ 0 \ n mod 2 = 1" + by (fact not_mod_2_eq_0_eq_1) + lemma Suc_0_div_numeral [simp]: fixes k l :: num shows "Suc 0 div numeral k = fst (divmod Num.One k)" @@ -1255,6 +382,27 @@ shows "Suc 0 mod numeral k = snd (divmod Num.One k)" by (simp_all add: snd_divmod) +definition divmod_nat :: "nat \ nat \ nat \ nat" + where "divmod_nat m n = (m div n, m mod n)" + +lemma fst_divmod_nat [simp]: + "fst (divmod_nat m n) = m div n" + by (simp add: divmod_nat_def) + +lemma snd_divmod_nat [simp]: + "snd (divmod_nat m n) = m mod n" + by (simp add: divmod_nat_def) + +lemma divmod_nat_if [code]: + "Divides.divmod_nat m n = (if n = 0 \ m < n then (0, m) else + let (q, r) = Divides.divmod_nat (m - n) n in (Suc q, r))" + by (simp add: prod_eq_iff case_prod_beta not_less le_div_geq le_mod_geq) + +lemma [code]: + "m div n = fst (divmod_nat m n)" + "m mod n = snd (divmod_nat m n)" + by simp_all + subsection \Division on @{typ int}\ @@ -2225,7 +1373,7 @@ lemma int_div_less_self: "\0 < x; 1 < k\ \ x div k < (x::int)" apply (subgoal_tac "nat x div nat k < nat x") apply (simp add: nat_div_distrib [symmetric]) -apply (rule Divides.div_less_dividend, simp_all) +apply (rule div_less_dividend, simp_all) done lemma nat_mod_eq_lemma: assumes xyn: "(x::nat) mod n = y mod n" and xy:"y \ x" @@ -2258,11 +1406,12 @@ thus ?lhs by simp qed + subsubsection \Dedicated simproc for calculation\ text \ There is space for improvement here: the calculation itself - could be carried outside the logic, and a generic simproc + could be carried out outside the logic, and a generic simproc (simplifier setup) for generic calculation would be helpful. \ @@ -2348,4 +1497,39 @@ declare minus_div_mult_eq_mod [symmetric, nitpick_unfold] + +subsubsection \Lemmas of doubtful value\ + +lemma mod_mult_self3': + "Suc (k * n + m) mod n = Suc m mod n" + by (fact Suc_mod_mult_self3) + +lemma mod_Suc_eq_Suc_mod: + "Suc m mod n = Suc (m mod n) mod n" + by (simp add: mod_simps) + +lemma div_geq: + "m div n = Suc ((m - n) div n)" if "0 < n" and " \ m < n" for m n :: nat + by (rule le_div_geq) (use that in \simp_all add: not_less\) + +lemma mod_geq: + "m mod n = (m - n) mod n" if "\ m < n" for m n :: nat + by (rule le_mod_geq) (use that in \simp add: not_less\) + +lemma mod_eq_0_iff: "(m mod d = 0) = (\q::nat. m = d*q)" + by (auto simp add: dvd_eq_mod_eq_0 [symmetric] dvd_def) + +lemmas mod_eq_0D [dest!] = mod_eq_0_iff [THEN iffD1] + +(*Loses information, namely we also have rq. m = r + q * d" +proof - + from div_mult_mod_eq obtain q where "q * d + m mod d = m" by blast + with assms have "m = r + q * d" by simp + then show ?thesis .. +qed + end diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Euclidean_Division.thy --- a/src/HOL/Euclidean_Division.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Euclidean_Division.thy Sun Oct 08 22:28:21 2017 +0200 @@ -6,9 +6,19 @@ section \Uniquely determined division in euclidean (semi)rings\ theory Euclidean_Division - imports Nat_Transfer + imports Nat_Transfer Lattices_Big begin +subsection \Prelude: simproc for cancelling @{const divide} and @{const modulo}\ + +lemma (in semiring_modulo) cancel_div_mod_rules: + "((a div b) * b + a mod b) + c = a + c" + "(b * (a div b) + a mod b) + c = a + c" + by (simp_all add: div_mult_mod_eq mult_div_mod_eq) + +ML_file "~~/src/Provers/Arith/cancel_div_mod.ML" + + subsection \Euclidean (semi)rings with explicit division and remainder\ class euclidean_semiring = semidom_modulo + normalization_semidom + @@ -639,4 +649,657 @@ end + +subsection \Euclidean division on @{typ nat}\ + +instantiation nat :: unique_euclidean_semiring +begin + +definition normalize_nat :: "nat \ nat" + where [simp]: "normalize = (id :: nat \ nat)" + +definition unit_factor_nat :: "nat \ nat" + where "unit_factor n = (if n = 0 then 0 else 1 :: nat)" + +lemma unit_factor_simps [simp]: + "unit_factor 0 = (0::nat)" + "unit_factor (Suc n) = 1" + by (simp_all add: unit_factor_nat_def) + +definition euclidean_size_nat :: "nat \ nat" + where [simp]: "euclidean_size_nat = id" + +definition uniqueness_constraint_nat :: "nat \ nat \ bool" + where [simp]: "uniqueness_constraint_nat = \" + +definition divide_nat :: "nat \ nat \ nat" + where "m div n = (if n = 0 then 0 else Max {k::nat. k * n \ m})" + +definition modulo_nat :: "nat \ nat \ nat" + where "m mod n = m - (m div n * (n::nat))" + +instance proof + fix m n :: nat + have ex: "\k. k * n \ l" for l :: nat + by (rule exI [of _ 0]) simp + have fin: "finite {k. k * n \ l}" if "n > 0" for l + proof - + from that have "{k. k * n \ l} \ {k. k \ l}" + by (cases n) auto + then show ?thesis + by (rule finite_subset) simp + qed + have mult_div_unfold: "n * (m div n) = Max {l. l \ m \ n dvd l}" + proof (cases "n = 0") + case True + moreover have "{l. l = 0 \ l \ m} = {0::nat}" + by auto + ultimately show ?thesis + by simp + next + case False + with ex [of m] fin have "n * Max {k. k * n \ m} = Max (times n ` {k. k * n \ m})" + by (auto simp add: nat_mult_max_right intro: hom_Max_commute) + also have "times n ` {k. k * n \ m} = {l. l \ m \ n dvd l}" + by (auto simp add: ac_simps elim!: dvdE) + finally show ?thesis + using False by (simp add: divide_nat_def ac_simps) + qed + show "n div 0 = 0" + by (simp add: divide_nat_def) + have less_eq: "m div n * n \ m" + by (auto simp add: mult_div_unfold ac_simps intro: Max.boundedI) + then show "m div n * n + m mod n = m" + by (simp add: modulo_nat_def) + assume "n \ 0" + show "m * n div n = m" + using \n \ 0\ by (auto simp add: divide_nat_def ac_simps intro: Max_eqI) + show "euclidean_size (m mod n) < euclidean_size n" + proof - + have "m < Suc (m div n) * n" + proof (rule ccontr) + assume "\ m < Suc (m div n) * n" + then have "Suc (m div n) * n \ m" + by (simp add: not_less) + moreover from \n \ 0\ have "Max {k. k * n \ m} < Suc (m div n)" + by (simp add: divide_nat_def) + with \n \ 0\ ex fin have "\k. k * n \ m \ k < Suc (m div n)" + by auto + ultimately have "Suc (m div n) < Suc (m div n)" + by blast + then show False + by simp + qed + with \n \ 0\ show ?thesis + by (simp add: modulo_nat_def) + qed + show "euclidean_size m \ euclidean_size (m * n)" + using \n \ 0\ by (cases n) simp_all + fix q r :: nat + show "(q * n + r) div n = q" if "euclidean_size r < euclidean_size n" + proof - + from that have "r < n" + by simp + have "k \ q" if "k * n \ q * n + r" for k + proof (rule ccontr) + assume "\ k \ q" + then have "q < k" + by simp + then obtain l where "k = Suc (q + l)" + by (auto simp add: less_iff_Suc_add) + with \r < n\ that show False + by (simp add: algebra_simps) + qed + with \n \ 0\ ex fin show ?thesis + by (auto simp add: divide_nat_def Max_eq_iff) + qed +qed (simp_all add: unit_factor_nat_def) + end + +text \Tool support\ + +ML \ +structure Cancel_Div_Mod_Nat = Cancel_Div_Mod +( + val div_name = @{const_name divide}; + val mod_name = @{const_name modulo}; + val mk_binop = HOLogic.mk_binop; + val mk_plus = HOLogic.mk_binop @{const_name Groups.plus}; + val dest_plus = HOLogic.dest_bin @{const_name Groups.plus} HOLogic.natT; + fun mk_sum [] = HOLogic.zero + | mk_sum [t] = t + | mk_sum (t :: ts) = mk_plus (t, mk_sum ts); + fun dest_sum tm = + if HOLogic.is_zero tm then [] + else + (case try HOLogic.dest_Suc tm of + SOME t => HOLogic.Suc_zero :: dest_sum t + | NONE => + (case try dest_plus tm of + SOME (t, u) => dest_sum t @ dest_sum u + | NONE => [tm])); + + val div_mod_eqs = map mk_meta_eq @{thms cancel_div_mod_rules}; + + val prove_eq_sums = Arith_Data.prove_conv2 all_tac + (Arith_Data.simp_all_tac @{thms add_0_left add_0_right ac_simps}) +) +\ + +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 + +lemma div_mult_self1_is_m [simp]: + "n * m div n = m" if "n > 0" for m n :: nat + using that by simp + +lemma mod_less_divisor [simp]: + "m mod n < n" if "n > 0" for m n :: nat + using mod_size_less [of n m] that by simp + +lemma mod_le_divisor [simp]: + "m mod n \ n" if "n > 0" for m n :: nat + using that by (auto simp add: le_less) + +lemma div_times_less_eq_dividend [simp]: + "m div n * n \ m" for m n :: nat + by (simp add: minus_mod_eq_div_mult [symmetric]) + +lemma times_div_less_eq_dividend [simp]: + "n * (m div n) \ m" for m n :: nat + using div_times_less_eq_dividend [of m n] + by (simp add: ac_simps) + +lemma dividend_less_div_times: + "m < n + (m div n) * n" if "0 < n" for m n :: nat +proof - + from that have "m mod n < n" + by simp + then show ?thesis + by (simp add: minus_mod_eq_div_mult [symmetric]) +qed + +lemma dividend_less_times_div: + "m < n + n * (m div n)" if "0 < n" for m n :: nat + using dividend_less_div_times [of n m] that + by (simp add: ac_simps) + +lemma mod_Suc_le_divisor [simp]: + "m mod Suc n \ n" + using mod_less_divisor [of "Suc n" m] by arith + +lemma mod_less_eq_dividend [simp]: + "m mod n \ m" for m n :: nat +proof (rule add_leD2) + from div_mult_mod_eq have "m div n * n + m mod n = m" . + then show "m div n * n + m mod n \ m" by auto +qed + +lemma + div_less [simp]: "m div n = 0" + 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 le_div_geq: + "m div n = Suc ((m - n) div n)" if "0 < n" and "n \ m" for m n :: nat +proof - + from \n \ m\ obtain q where "m = n + q" + by (auto simp add: le_iff_add) + with \0 < n\ show ?thesis + by (simp add: div_add_self1) +qed + +lemma le_mod_geq: + "m mod n = (m - n) mod n" if "n \ m" for m n :: nat +proof - + from \n \ m\ obtain q where "m = n + q" + by (auto simp add: le_iff_add) + then show ?thesis + by simp +qed + +lemma div_if: + "m div n = (if m < n \ n = 0 then 0 else Suc ((m - n) div n))" + by (simp add: le_div_geq) + +lemma mod_if: + "m mod n = (if m < n then m else (m - n) mod n)" for m n :: nat + by (simp add: le_mod_geq) + +lemma div_eq_0_iff: + "m div n = 0 \ m < n \ n = 0" for m n :: nat + by (simp add: div_if) + +lemma div_greater_zero_iff: + "m div n > 0 \ n \ m \ n > 0" for m n :: nat + using div_eq_0_iff [of m n] by auto + +lemma mod_greater_zero_iff_not_dvd: + "m mod n > 0 \ \ n dvd m" for m n :: nat + by (simp add: dvd_eq_mod_eq_0) + +lemma div_by_Suc_0 [simp]: + "m div Suc 0 = m" + using div_by_1 [of m] by simp + +lemma mod_by_Suc_0 [simp]: + "m mod Suc 0 = 0" + using mod_by_1 [of m] by simp + +lemma div2_Suc_Suc [simp]: + "Suc (Suc m) div 2 = Suc (m div 2)" + by (simp add: numeral_2_eq_2 le_div_geq) + +lemma Suc_n_div_2_gt_zero [simp]: + "0 < Suc n div 2" if "n > 0" for n :: nat + using that by (cases n) simp_all + +lemma div_2_gt_zero [simp]: + "0 < n div 2" if "Suc 0 < n" for n :: nat + using that Suc_n_div_2_gt_zero [of "n - 1"] by simp + +lemma mod2_Suc_Suc [simp]: + "Suc (Suc m) mod 2 = m mod 2" + by (simp add: numeral_2_eq_2 le_mod_geq) + +lemma add_self_div_2 [simp]: + "(m + m) div 2 = m" for m :: nat + by (simp add: mult_2 [symmetric]) + +lemma add_self_mod_2 [simp]: + "(m + m) mod 2 = 0" for m :: nat + by (simp add: mult_2 [symmetric]) + +lemma mod2_gr_0 [simp]: + "0 < m mod 2 \ m mod 2 = 1" for m :: nat +proof - + have "m mod 2 < 2" + by (rule mod_less_divisor) simp + then have "m mod 2 = 0 \ m mod 2 = 1" + by arith + then show ?thesis + by auto +qed + +lemma mod_Suc_eq [mod_simps]: + "Suc (m mod n) mod n = Suc m mod n" +proof - + have "(m mod n + 1) mod n = (m + 1) mod n" + by (simp only: mod_simps) + then show ?thesis + by simp +qed + +lemma mod_Suc_Suc_eq [mod_simps]: + "Suc (Suc (m mod n)) mod n = Suc (Suc m) mod n" +proof - + have "(m mod n + 2) mod n = (m + 2) mod n" + by (simp only: mod_simps) + then show ?thesis + by simp +qed + +lemma + Suc_mod_mult_self1 [simp]: "Suc (m + k * n) mod n = Suc m mod n" + and Suc_mod_mult_self2 [simp]: "Suc (m + n * k) mod n = Suc m mod n" + and Suc_mod_mult_self3 [simp]: "Suc (k * n + m) mod n = Suc m mod n" + and Suc_mod_mult_self4 [simp]: "Suc (n * k + m) mod n = Suc m mod n" + by (subst mod_Suc_eq [symmetric], simp add: mod_simps)+ + +lemma div_mult1_eq: -- \TODO: Generalization candidate\ + "(a * b) div c = a * (b div c) + a * (b mod c) div c" for a b c :: nat + apply (cases "c = 0") + apply simp + apply (rule div_eqI [of _ "(a * (b mod c)) mod c"]) + apply (auto simp add: algebra_simps distrib_left [symmetric]) + done + +lemma div_add1_eq: -- \NOT suitable for rewriting: the RHS has an instance of the LHS\ + -- \TODO: Generalization candidate\ + "(a + b) div c = a div c + b div c + ((a mod c + b mod c) div c)" for a b c :: nat + apply (cases "c = 0") + apply simp + apply (rule div_eqI [of _ "(a mod c + b mod c) mod c"]) + apply (auto simp add: algebra_simps) + done + +context + fixes m n q :: nat +begin + +private lemma eucl_rel_mult2: + "m mod n + n * (m div n mod q) < n * q" + if "n > 0" and "q > 0" +proof - + from \n > 0\ have "m mod n < n" + by (rule mod_less_divisor) + from \q > 0\ have "m div n mod q < q" + by (rule mod_less_divisor) + then obtain s where "q = Suc (m div n mod q + s)" + by (blast dest: less_imp_Suc_add) + moreover have "m mod n + n * (m div n mod q) < n * Suc (m div n mod q + s)" + using \m mod n < n\ by (simp add: add_mult_distrib2) + ultimately show ?thesis + by simp +qed + +lemma div_mult2_eq: + "m div (n * q) = (m div n) div q" +proof (cases "n = 0 \ q = 0") + case True + then show ?thesis + by auto +next + case False + with eucl_rel_mult2 show ?thesis + by (auto intro: div_eqI [of _ "n * (m div n mod q) + m mod n"] + simp add: algebra_simps add_mult_distrib2 [symmetric]) +qed + +lemma mod_mult2_eq: + "m mod (n * q) = n * (m div n mod q) + m mod n" +proof (cases "n = 0 \ q = 0") + case True + then show ?thesis + by auto +next + case False + with eucl_rel_mult2 show ?thesis + by (auto intro: mod_eqI [of _ _ "(m div n) div q"] + simp add: algebra_simps add_mult_distrib2 [symmetric]) +qed + +end + +lemma div_le_mono: + "m div k \ n div k" if "m \ n" for m n k :: nat +proof - + from that obtain q where "n = m + q" + by (auto simp add: le_iff_add) + then show ?thesis + by (simp add: div_add1_eq [of m q k]) +qed + +text \Antimonotonicity of @{const divide} in second argument\ + +lemma div_le_mono2: + "k div n \ k div m" if "0 < m" and "m \ n" for m n k :: nat +using that proof (induct k arbitrary: m rule: less_induct) + case (less k) + show ?case + proof (cases "n \ k") + case False + then show ?thesis + by simp + next + case True + have "(k - n) div n \ (k - m) div n" + using less.prems + by (blast intro: div_le_mono diff_le_mono2) + also have "\ \ (k - m) div m" + using \n \ k\ less.prems less.hyps [of "k - m" m] + by simp + finally show ?thesis + using \n \ k\ less.prems + by (simp add: le_div_geq) + qed +qed + +lemma div_le_dividend [simp]: + "m div n \ m" for m n :: nat + using div_le_mono2 [of 1 n m] by (cases "n = 0") simp_all + +lemma div_less_dividend [simp]: + "m div n < m" if "1 < n" and "0 < m" for m n :: nat +using that proof (induct m rule: less_induct) + case (less m) + show ?case + proof (cases "n < m") + case False + with less show ?thesis + by (cases "n = m") simp_all + next + case True + then show ?thesis + using less.hyps [of "m - n"] less.prems + by (simp add: le_div_geq) + qed +qed + +lemma div_eq_dividend_iff: + "m div n = m \ n = 1" if "m > 0" for m n :: nat +proof + assume "n = 1" + then show "m div n = m" + by simp +next + assume P: "m div n = m" + show "n = 1" + proof (rule ccontr) + have "n \ 0" + by (rule ccontr) (use that P in auto) + moreover assume "n \ 1" + ultimately have "n > 1" + by simp + with that have "m div n < m" + by simp + with P show False + by simp + qed +qed + +lemma less_mult_imp_div_less: + "m div n < i" if "m < i * n" for m n i :: nat +proof - + from that have "i * n > 0" + by (cases "i * n = 0") simp_all + then have "i > 0" and "n > 0" + by simp_all + have "m div n * n \ m" + by simp + then have "m div n * n < i * n" + using that by (rule le_less_trans) + with \n > 0\ show ?thesis + by simp +qed + +text \A fact for the mutilated chess board\ + +lemma mod_Suc: + "Suc m mod n = (if Suc (m mod n) = n then 0 else Suc (m mod n))" (is "_ = ?rhs") +proof (cases "n = 0") + case True + then show ?thesis + by simp +next + case False + have "Suc m mod n = Suc (m mod n) mod n" + by (simp add: mod_simps) + also have "\ = ?rhs" + using False by (auto intro!: mod_nat_eqI intro: neq_le_trans simp add: Suc_le_eq) + finally show ?thesis . +qed + +lemma Suc_times_mod_eq: + "Suc (m * n) mod m = 1" if "Suc 0 < m" + using that by (simp add: mod_Suc) + +lemma Suc_times_numeral_mod_eq [simp]: + "Suc (numeral k * n) mod numeral k = 1" if "numeral k \ (1::nat)" + by (rule Suc_times_mod_eq) (use that in simp) + +lemma Suc_div_le_mono [simp]: + "m div n \ Suc m div n" + by (simp add: div_le_mono) + +text \These lemmas collapse some needless occurrences of Suc: + at least three Sucs, since two and fewer are rewritten back to Suc again! + We already have some rules to simplify operands smaller than 3.\ + +lemma div_Suc_eq_div_add3 [simp]: + "m div Suc (Suc (Suc n)) = m div (3 + n)" + by (simp add: Suc3_eq_add_3) + +lemma mod_Suc_eq_mod_add3 [simp]: + "m mod Suc (Suc (Suc n)) = m mod (3 + n)" + by (simp add: Suc3_eq_add_3) + +lemma Suc_div_eq_add3_div: + "Suc (Suc (Suc m)) div n = (3 + m) div n" + by (simp add: Suc3_eq_add_3) + +lemma Suc_mod_eq_add3_mod: + "Suc (Suc (Suc m)) mod n = (3 + m) mod n" + by (simp add: Suc3_eq_add_3) + +lemmas Suc_div_eq_add3_div_numeral [simp] = + Suc_div_eq_add3_div [of _ "numeral v"] for v + +lemmas Suc_mod_eq_add3_mod_numeral [simp] = + Suc_mod_eq_add3_mod [of _ "numeral v"] for v + +lemma (in field_char_0) of_nat_div: + "of_nat (m div n) = ((of_nat m - of_nat (m mod n)) / of_nat n)" +proof - + have "of_nat (m div n) = ((of_nat (m div n * n + m mod n) - of_nat (m mod n)) / of_nat n :: 'a)" + unfolding of_nat_add by (cases "n = 0") simp_all + then show ?thesis + by simp +qed + +text \An ``induction'' law for modulus arithmetic.\ + +lemma mod_induct [consumes 3, case_names step]: + "P m" if "P n" and "n < p" and "m < p" + and step: "\n. n < p \ P n \ P (Suc n mod p)" +using \m < p\ proof (induct m) + case 0 + show ?case + proof (rule ccontr) + assume "\ P 0" + from \n < p\ have "0 < p" + by simp + from \n < p\ obtain m where "0 < m" and "p = n + m" + by (blast dest: less_imp_add_positive) + with \P n\ have "P (p - m)" + by simp + moreover have "\ P (p - m)" + using \0 < m\ proof (induct m) + case 0 + then show ?case + by simp + next + case (Suc m) + show ?case + proof + assume P: "P (p - Suc m)" + with \\ P 0\ have "Suc m < p" + by (auto intro: ccontr) + then have "Suc (p - Suc m) = p - m" + by arith + moreover from \0 < p\ have "p - Suc m < p" + by arith + with P step have "P ((Suc (p - Suc m)) mod p)" + by blast + ultimately show False + using \\ P 0\ Suc.hyps by (cases "m = 0") simp_all + qed + qed + ultimately show False + by blast + qed +next + case (Suc m) + then have "m < p" and mod: "Suc m mod p = Suc m" + by simp_all + from \m < p\ have "P m" + by (rule Suc.hyps) + with \m < p\ have "P (Suc m mod p)" + by (rule step) + with mod show ?case + 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 + + +subsection \Code generation\ + +code_identifier + code_module Euclidean_Division \ (SML) Arith and (OCaml) Arith and (Haskell) Arith + +end diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Library/Code_Target_Nat.thy --- a/src/HOL/Library/Code_Target_Nat.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Library/Code_Target_Nat.thy Sun Oct 08 22:28:21 2017 +0200 @@ -95,7 +95,7 @@ lemma [code]: "Divides.divmod_nat m n = (m div n, m mod n)" - by (fact divmod_nat_div_mod) + by (fact divmod_nat_def) lemma [code]: "divmod m n = map_prod nat_of_integer nat_of_integer (divmod m n)" @@ -130,7 +130,7 @@ proof - from div_mult_mod_eq have *: "of_nat n = of_nat (n div 2 * 2 + n mod 2)" by simp show ?thesis - by (simp add: Let_def divmod_nat_div_mod of_nat_add [symmetric]) + by (simp add: Let_def divmod_nat_def of_nat_add [symmetric]) (simp add: * mult.commute of_nat_mult add.commute) qed diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Library/RBT_Impl.thy --- a/src/HOL/Library/RBT_Impl.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Library/RBT_Impl.thy Sun Oct 08 22:28:21 2017 +0200 @@ -1169,7 +1169,7 @@ apfst (Branch B t1 k v) (rbtreeify_g n' kvs') else case rbtreeify_f n' kvs of (t1, (k, v) # kvs') \ apfst (Branch B t1 k v) (rbtreeify_f n' kvs'))" -by (subst rbtreeify_f.simps) (simp only: Let_def divmod_nat_div_mod prod.case) +by (subst rbtreeify_f.simps) (simp only: Let_def divmod_nat_def prod.case) lemma rbtreeify_g_code [code]: "rbtreeify_g n kvs = @@ -1180,7 +1180,7 @@ apfst (Branch B t1 k v) (rbtreeify_g n' kvs') else case rbtreeify_f n' kvs of (t1, (k, v) # kvs') \ apfst (Branch B t1 k v) (rbtreeify_g n' kvs'))" -by(subst rbtreeify_g.simps)(simp only: Let_def divmod_nat_div_mod prod.case) +by(subst rbtreeify_g.simps)(simp only: Let_def divmod_nat_def prod.case) lemma Suc_double_half: "Suc (2 * n) div 2 = n" by simp diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Parity.thy --- a/src/HOL/Parity.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Parity.thy Sun Oct 08 22:28:21 2017 +0200 @@ -101,6 +101,92 @@ end +class unique_euclidean_semiring_parity = unique_euclidean_semiring + + assumes parity: "a mod 2 = 0 \ a mod 2 = 1" + assumes one_mod_two_eq_one [simp]: "1 mod 2 = 1" + assumes zero_not_eq_two: "0 \ 2" +begin + +lemma parity_cases [case_names even odd]: + assumes "a mod 2 = 0 \ P" + assumes "a mod 2 = 1 \ P" + shows P + using assms parity by blast + +lemma one_div_two_eq_zero [simp]: + "1 div 2 = 0" +proof (cases "2 = 0") + case True then show ?thesis by simp +next + case False + from div_mult_mod_eq have "1 div 2 * 2 + 1 mod 2 = 1" . + with one_mod_two_eq_one have "1 div 2 * 2 + 1 = 1" by simp + then have "1 div 2 * 2 = 0" by (simp add: ac_simps add_left_imp_eq del: mult_eq_0_iff) + then have "1 div 2 = 0 \ 2 = 0" by simp + with False show ?thesis by auto +qed + +lemma not_mod_2_eq_0_eq_1 [simp]: + "a mod 2 \ 0 \ a mod 2 = 1" + by (cases a rule: parity_cases) simp_all + +lemma not_mod_2_eq_1_eq_0 [simp]: + "a mod 2 \ 1 \ a mod 2 = 0" + by (cases a rule: parity_cases) simp_all + +subclass semiring_parity +proof (unfold_locales, unfold dvd_eq_mod_eq_0 not_mod_2_eq_0_eq_1) + show "1 mod 2 = 1" + by (fact one_mod_two_eq_one) +next + fix a b + assume "a mod 2 = 1" + moreover assume "b mod 2 = 1" + ultimately show "(a + b) mod 2 = 0" + using mod_add_eq [of a 2 b] by simp +next + fix a b + assume "(a * b) mod 2 = 0" + then have "(a mod 2) * (b mod 2) mod 2 = 0" + by (simp add: mod_mult_eq) + then have "(a mod 2) * (b mod 2) = 0" + by (cases "a mod 2 = 0") simp_all + then show "a mod 2 = 0 \ b mod 2 = 0" + by (rule divisors_zero) +next + fix a + assume "a mod 2 = 1" + then have "a = a div 2 * 2 + 1" + using div_mult_mod_eq [of a 2] by simp + then show "\b. a = b + 1" .. +qed + +lemma even_iff_mod_2_eq_zero: + "even a \ a mod 2 = 0" + by (fact dvd_eq_mod_eq_0) + +lemma odd_iff_mod_2_eq_one: + "odd a \ a mod 2 = 1" + by (simp add: even_iff_mod_2_eq_zero) + +lemma even_succ_div_two [simp]: + "even a \ (a + 1) div 2 = a div 2" + by (cases "a = 0") (auto elim!: evenE dest: mult_not_zero) + +lemma odd_succ_div_two [simp]: + "odd a \ (a + 1) div 2 = a div 2 + 1" + by (auto elim!: oddE simp add: zero_not_eq_two [symmetric] add.assoc) + +lemma even_two_times_div_two: + "even a \ 2 * (a div 2) = a" + by (fact dvd_mult_div_cancel) + +lemma odd_two_times_div_two_succ [simp]: + "odd a \ 2 * (a div 2) + 1 = a" + using mult_div_mod_eq [of 2 a] by (simp add: even_iff_mod_2_eq_zero) + +end + subsection \Instances for @{typ nat} and @{typ int}\ @@ -190,9 +276,6 @@ for k l :: int using even_abs_add_iff [of l k] by (simp add: ac_simps) -lemma odd_Suc_minus_one [simp]: "odd n \ Suc (n - Suc 0) = n" - by (auto elim: oddE) - instance int :: ring_parity proof show "\ 2 dvd (1 :: int)" diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Rings.thy --- a/src/HOL/Rings.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Rings.thy Sun Oct 08 22:28:21 2017 +0200 @@ -1620,6 +1620,10 @@ shows "c dvd a" using assms dvd_mod_iff [of c b a] by simp +lemma dvd_minus_mod [simp]: + "b dvd a - a mod b" + by (simp add: minus_mod_eq_div_mult) + end class idom_modulo = idom + semidom_modulo diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Word/Word.thy --- a/src/HOL/Word/Word.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Word/Word.thy Sun Oct 08 22:28:21 2017 +0200 @@ -2024,7 +2024,7 @@ lemmas le_unat_uoi = unat_le [THEN word_unat.Abs_inverse] -lemmas thd = refl [THEN [2] split_div_lemma [THEN iffD2], THEN conjunct1] +lemmas thd = times_div_less_eq_dividend lemmas uno_simps [THEN le_unat_uoi] = mod_le_divisor div_le_dividend dtle @@ -3724,7 +3724,7 @@ lemmas length_word_rsplit_exp_size' = refl [THEN length_word_rsplit_exp_size] (* alternative proof of word_rcat_rsplit *) -lemmas tdle = iffD2 [OF split_div_lemma refl, THEN conjunct1] +lemmas tdle = times_div_less_eq_dividend lemmas dtle = xtr4 [OF tdle mult.commute] lemma word_rcat_rsplit: "word_rcat (word_rsplit w) = w" @@ -3734,7 +3734,7 @@ apply (simp_all add: word_size refl [THEN length_word_rsplit_size [simplified not_less [symmetric], simplified]]) apply safe - apply (erule xtr7, rule len_gt_0 [THEN dtle])+ + apply (erule xtr7, rule dtle)+ done lemma size_word_rsplit_rcat_size: diff -r c3631f32dfeb -r 1907167b6038 src/HOL/Word/Word_Miscellaneous.thy --- a/src/HOL/Word/Word_Miscellaneous.thy Sun Oct 08 22:28:21 2017 +0200 +++ b/src/HOL/Word/Word_Miscellaneous.thy Sun Oct 08 22:28:21 2017 +0200 @@ -304,8 +304,8 @@ lemmas pl_pl_mm' = add.commute [THEN [2] trans, THEN pl_pl_mm] lemmas dme = div_mult_mod_eq -lemmas dtle = xtr3 [OF dme [symmetric] le_add1] -lemmas th2 = order_trans [OF order_refl [THEN [2] mult_le_mono] dtle] +lemmas dtle = div_times_less_eq_dividend +lemmas th2 = order_trans [OF order_refl [THEN [2] mult_le_mono] div_times_less_eq_dividend] lemma td_gal: "0 < c \ a \ b * c \ a div c \ b" for a b c :: nat @@ -316,15 +316,13 @@ lemmas td_gal_lt = td_gal [simplified not_less [symmetric], simplified] -lemma div_mult_le: "a div b * b \ a" - for a b :: nat - by (fact dtle) +lemmas div_mult_le = div_times_less_eq_dividend -lemmas sdl = split_div_lemma [THEN iffD1, symmetric] +lemmas sdl = div_nat_eqI lemma given_quot: "f > 0 \ (f * l + (f - 1)) div f = l" for f l :: nat - by (rule sdl, assumption) (simp (no_asm)) + by (rule div_nat_eqI) (simp_all) lemma given_quot_alt: "f > 0 \ (l * f + f - Suc 0) div f = l" for f l :: nat