typedef 'a multiset = ‹{f :: 'a ==> nat. finite {x. f x > 0}}› morphisms count Abs_multiset proof show‹(λx. 0::nat) ∈ {f. finite {x. f x > 0}}› by simp qed
setup_lifting type_definition_multiset
lemma count_Abs_multiset: ‹count (Abs_multiset f) = f›if‹finite {x. f x > 0}› by (rule Abs_multiset_inverse) (simp add: that)
lemma multiset_eq_iff: "M = N ⟷ (∀a. count M a = count N a)" by (simp only: count_inject [symmetric] fun_eq_iff)
lemma multiset_eqI: "(∧x. count A x = count B x) ==> A = B" using multiset_eq_iff by auto
text‹Preservation of the representing set term‹multiset›.›
lemma diff_preserves_multiset: ‹finite {x. 0 < M x - N x}›if‹finite {x. 0 < M x}›for M N :: ‹'a ==> nat› using that by (rule rev_finite_subset) auto
lemma filter_preserves_multiset: ‹finite {x. 0 < (if P x then M x else 0)}›if‹finite {x. 0 < M x}›for M N :: ‹'a ==> nat› using that by (rule rev_finite_subset) auto
lift_definition plus_multiset :: ‹'a multiset ==> 'a multiset ==> 'a multiset› is‹λM N a. M a + N a› by simp
lift_definition minus_multiset :: ‹'a multiset ==> 'a multiset ==> 'a multiset› is‹λM N a. M a - N a› by (rule diff_preserves_multiset)
instance by (standard; transfer) (simp_all add: fun_eq_iff)
end
context begin
qualified definition is_empty :: "'a multiset ==> bool"where
[code_abbrev]: "is_empty A ⟷ A = {#}"
end
lemma add_mset_in_multiset: ‹finite {x. 0 < (if x = a then Suc (M x) else M x)}› if‹finite {x. 0 < M x}› using that by (simp add: flip: insert_Collect)
lift_definition add_mset :: "'a ==> 'a multiset ==> 'a multiset"is "λa M b. if b = a then Suc (M b) else M b" by (rule add_mset_in_multiset)
syntax "_multiset" :: "args ==> 'a multiset" (‹(‹indent=2 notation=‹mixfix multiset enumeration››{#_#})›)
syntax_consts "_multiset"⇌ add_mset translations "{#x, xs#}" == "CONST add_mset x {#xs#}" "{#x#}" == "CONST add_mset x {#}"
lemma count_empty [simp]: "count {#} a = 0" by (simp add: zero_multiset.rep_eq)
lemma count_add_mset [simp]: "count (add_mset b A) a = (if b = a then Suc (count A a) else count A a)" by (simp add: add_mset.rep_eq)
lemma count_single: "count {#b#} a = (if b = a then 1 else 0)" by simp
lemma
add_mset_not_empty [simp]: ‹add_mset a A ≠ {#}›and
empty_not_add_mset [simp]: "{#} ≠ add_mset a A" by (auto simp: multiset_eq_iff)
lemma add_mset_add_mset_same_iff [simp]: "add_mset a A = add_mset a B ⟷ A = B" by (auto simp: multiset_eq_iff)
lemma add_mset_commute: "add_mset x (add_mset y M) = add_mset y (add_mset x M)" by (auto simp: multiset_eq_iff)
subsection‹Basic operations›
subsubsection‹Conversion to set and membership›
definition set_mset :: ‹'a multiset ==> 'a set› where‹set_mset M = {x. count M x > 0}›
abbreviation member_mset :: ‹'a ==> 'a multiset ==> bool› where‹member_mset a M ≡ a ∈ set_mset M›
lemma count_eq_zero_iff: "count M x = 0 ⟷ x ∉# M" by (auto simp add: set_mset_def)
lemma not_in_iff: "x ∉# M ⟷ count M x = 0" by (auto simp add: count_eq_zero_iff)
lemma count_greater_zero_iff [simp]: "count M x > 0 ⟷ x ∈# M" by (auto simp add: set_mset_def)
lemma count_inI: assumes"count M x = 0 ==> False" shows"x ∈# M" proof (rule ccontr) assume"x ∉# M" with assms show False by (simp add: not_in_iff) qed
lemma in_countE: assumes"x ∈# M" obtains n where"count M x = Suc n" proof - from assms have"count M x > 0"by simp thenobtain n where"count M x = Suc n" using gr0_conv_Suc by blast with that show thesis . qed
lemma count_greater_eq_Suc_zero_iff [simp]: "count M x ≥ Suc 0 ⟷ x ∈# M" by (simp add: Suc_le_eq)
lemma count_greater_eq_one_iff [simp]: "count M x ≥ 1 ⟷ x ∈# M" by simp
lemma set_mset_single: "set_mset {#b#} = {b}" by (simp add: set_mset_def)
lemma set_mset_eq_empty_iff [simp]: "set_mset M = {} ⟷ M = {#}" by (auto simp add: multiset_eq_iff count_eq_zero_iff)
lemma finite_set_mset [iff]: "finite (set_mset M)" using count [of M] by simp
lemma set_mset_add_mset_insert [simp]: ‹set_mset (add_mset a A) = insert a (set_mset A)› by (auto simp flip: count_greater_eq_Suc_zero_iff split: if_splits)
lemma multiset_nonemptyE [elim]: assumes"A ≠ {#}" obtains x where"x ∈# A" proof - have"∃x. x ∈# A"by (rule ccontr) (insert assms, auto) with that show ?thesis by blast qed
lemma count_gt_imp_in_mset: "count M x > n ==> x ∈# M" using count_greater_zero_iff by fastforce
subsubsection‹Union›
lemma count_union [simp]: "count (M + N) a = count M a + count N a" by (simp add: plus_multiset.rep_eq)
lemma union_mset_add_mset_left [simp]: "add_mset a A + B = add_mset a (A + B)" by (auto simp: multiset_eq_iff)
lemma union_mset_add_mset_right [simp]: "A + add_mset a B = add_mset a (A + B)" by (auto simp: multiset_eq_iff)
(* TODO: reverse arguments to prevent unfolding loop *) lemma add_mset_add_single: ‹add_mset a A = A + {#a#}› by (subst union_mset_add_mset_right, subst add.comm_neutral) standard
subsubsection‹Difference›
instance multiset :: (type) comm_monoid_diff by standard (transfer; simp add: fun_eq_iff)
lemma count_diff [simp]: "count (M - N) a = count M a - count N a" by (simp add: minus_multiset.rep_eq)
lemma add_mset_diff_bothsides: ‹add_mset a M - add_mset a A = M - A› by (auto simp: multiset_eq_iff)
lemma in_diff_count: "a ∈# M - N ⟷ count N a < count M a" by (simp add: set_mset_def)
lemma count_in_diffI: assumes"∧n. count N x = n + count M x ==> False" shows"x ∈# M - N" proof (rule ccontr) assume"x ∉# M - N" thenhave"count N x = (count N x - count M x) + count M x" by (simp add: in_diff_count not_less) with assms show False by auto qed
lemma in_diff_countE: assumes"x ∈# M - N" obtains n where"count M x = Suc n + count N x" proof - from assms have"count M x - count N x > 0"by (simp add: in_diff_count) thenhave"count M x > count N x"by simp thenobtain n where"count M x = Suc n + count N x" using less_iff_Suc_add by auto with that show thesis . qed
lemma in_diffD: assumes"a ∈# M - N" shows"a ∈# M" proof - have"0 ≤ count N a"by simp alsofrom assms have"count N a < count M a" by (simp add: in_diff_count) finallyshow ?thesis by simp qed
lemma set_mset_diff: "set_mset (M - N) = {a. count N a < count M a}" by (simp add: set_mset_def)
lemma diff_empty [simp]: "M - {#} = M ∧ {#} - M = {#}" by rule (fact Groups.diff_zero, fact Groups.zero_diff)
lemma diff_cancel: "A - A = {#}" by (fact Groups.diff_cancel)
lemma diff_union_cancelR: "M + N - N = (M::'a multiset)" by (fact add_diff_cancel_right')
lemma diff_union_cancelL: "N + M - N = (M::'a multiset)" by (fact add_diff_cancel_left')
lemma diff_right_commute: fixes M N Q :: "'a multiset" shows"M - N - Q = M - Q - N" by (fact diff_right_commute)
lemma diff_add: fixes M N Q :: "'a multiset" shows"M - (N + Q) = M - N - Q" by (rule sym) (fact diff_diff_add)
lemma insert_DiffM [simp]: "x ∈# M ==> add_mset x (M - {#x#}) = M" by (clarsimp simp: multiset_eq_iff)
lemma insert_DiffM2: "x ∈# M ==> (M - {#x#}) + {#x#} = M" by simp
lemma diff_union_swap: "a ≠ b ==> add_mset b (M - {#a#}) = add_mset b M - {#a#}" by (auto simp add: multiset_eq_iff)
lemma diff_add_mset_swap [simp]: "b ∉# A ==> add_mset b M - A = add_mset b (M - A)" by (auto simp add: multiset_eq_iff simp: not_in_iff)
lemma diff_union_swap2 [simp]: "y ∈# M ==> add_mset x M - {#y#} = add_mset x (M - {#y#})" by (metis add_mset_diff_bothsides diff_union_swap diff_zero insert_DiffM)
lemma diff_diff_add_mset [simp]: "(M::'a multiset) - N - P = M - (N + P)" by (rule diff_diff_add)
lemma diff_union_single_conv: "a ∈# J ==> I + J - {#a#} = I + (J - {#a#})" by (simp add: multiset_eq_iff Suc_le_eq)
lemma mset_add [elim?]: assumes"a ∈# A" obtains B where"A = add_mset a B" proof - from assms have"A = add_mset a (A - {#a#})" by simp with that show thesis . qed
lemma union_iff: "a ∈# A + B ⟷ a ∈# A ∨ a ∈# B" by auto
lemma count_minus_inter_lt_count_minus_inter_iff: "count (M2 - M1) y < count (M1 - M2) y ⟷ y ∈# M1 - M2" by (meson count_greater_zero_iff gr_implies_not_zero in_diff_count leI order.strict_trans2
order_less_asym)
abbreviation Min_mset :: "'a::linorder multiset ==> 'a"where "Min_mset m ≡ Min (set_mset m)"
abbreviation Max_mset :: "'a::linorder multiset ==> 'a"where "Max_mset m ≡ Max (set_mset m)"
lemma
Min_in_mset: "M ≠ {#} ==> Min_mset M ∈# M"and
Max_in_mset: "M ≠ {#} ==> Max_mset M ∈# M" by simp+
subsubsection‹Equality of multisets›
lemma single_eq_single [simp]: "{#a#} = {#b#} ⟷ a = b" by (auto simp add: multiset_eq_iff)
lemma union_eq_empty [iff]: "M + N = {#} ⟷ M = {#} ∧ N = {#}" by (auto simp add: multiset_eq_iff)
lemma empty_eq_union [iff]: "{#} = M + N ⟷ M = {#} ∧ N = {#}" by (auto simp add: multiset_eq_iff)
lemma multi_self_add_other_not_self [simp]: "M = add_mset x M ⟷ False" by (auto simp add: multiset_eq_iff)
lemma add_mset_remove_trivial [simp]: ‹add_mset x M - {#x#} = M› by (auto simp: multiset_eq_iff)
lemma diff_single_trivial: "¬ x ∈# M ==> M - {#x#} = M" by (auto simp add: multiset_eq_iff not_in_iff)
lemma diff_single_eq_union: "x ∈# M ==> M - {#x#} = N ⟷ M = add_mset x N" by auto
lemma union_single_eq_diff: "add_mset x M = N ==> M = N - {#x#}" unfolding add_mset_add_single[of _ M] by (fact add_implies_diff)
lemma union_single_eq_member: "add_mset x M = N ==> x ∈# N" by auto
lemma add_mset_remove_trivial_If: "add_mset a (N - {#a#}) = (if a ∈# N then N else add_mset a N)" by (simp add: diff_single_trivial)
lemma add_mset_remove_trivial_eq: ‹N = add_mset a (N - {#a#}) ⟷ a ∈# N› by (auto simp: add_mset_remove_trivial_If)
lemma union_is_single: "M + N = {#a#} ⟷ M = {#a#} ∧ N = {#} ∨ M = {#} ∧ N = {#a#}"
(is"?lhs = ?rhs") proof show ?lhs if ?rhs using that by auto show ?rhs if ?lhs by (metis Multiset.diff_cancel add.commute add_diff_cancel_left' diff_add_zero diff_single_trivial insert_DiffM that) qed
lemma single_is_union: "{#a#} = M + N ⟷ {#a#} = M ∧ N = {#} ∨ M = {#} ∧ {#a#} = N" by (auto simp add: eq_commute [of "{#a#}""M + N"] union_is_single)
lemma add_eq_conv_diff: "add_mset a M = add_mset b N ⟷ M = N ∧ a = b ∨ M = add_mset b (N - {#a#}) ∧ N = add_mset a (M - {#b#})"
(is"?lhs ⟷ ?rhs") (* shorter: by (simp add: multiset_eq_iff) fastforce *) proof show ?lhs if ?rhs using that by (auto simp add: add_mset_commute[of a b]) show ?rhs if ?lhs proof (cases "a = b") case True with‹?lhs›show ?thesis by simp next case False from‹?lhs›have"a ∈# add_mset b N"by (rule union_single_eq_member) with False have"a ∈# N"by auto moreoverfrom‹?lhs›have"M = add_mset b N - {#a#}"by (rule union_single_eq_diff) moreovernote False ultimatelyshow ?thesis by (auto simp add: diff_right_commute [of _ "{#a#}"]) qed qed
lemma add_mset_eq_single [iff]: "add_mset b M = {#a#} ⟷ b = a ∧ M = {#}" by (auto simp: add_eq_conv_diff)
lemma single_eq_add_mset [iff]: "{#a#} = add_mset b M ⟷ b = a ∧ M = {#}" by (auto simp: add_eq_conv_diff)
lemma insert_noteq_member: assumes BC: "add_mset b B = add_mset c C" and bnotc: "b ≠ c" shows"c ∈# B" proof - have"c ∈# add_mset c C"by simp have nc: "¬ c ∈# {#b#}"using bnotc by simp thenhave"c ∈# add_mset b B"using BC by simp thenshow"c ∈# B"using nc by simp qed
lemma add_eq_conv_ex: "(add_mset a M = add_mset b N) = (M = N ∧ a = b ∨ (∃K. M = add_mset b K ∧ N = add_mset a K))" by (auto simp add: add_eq_conv_diff)
lemma multi_member_split: "x ∈# M ==>∃A. M = add_mset x A" by (rule exI [where x = "M - {#x#}"]) simp
lemma multiset_add_sub_el_shuffle: assumes"c ∈# B" and"b ≠ c" shows"add_mset b (B - {#c#}) = add_mset b B - {#c#}" proof - from‹c ∈# B›obtain A where B: "B = add_mset c A" by (blast dest: multi_member_split) have"add_mset b A = add_mset c (add_mset b A) - {#c#}"by simp thenhave"add_mset b A = add_mset b (add_mset c A) - {#c#}" by (simp add: ‹b ≠ c›) thenshow ?thesis using B by simp qed
lemma add_mset_eq_singleton_iff[iff]: "add_mset x M = {#y#} ⟷ M = {#} ∧ x = y" by auto
subsubsection‹Pointwise ordering induced by count›
definition subseteq_mset :: "'a multiset ==> 'a multiset ==> bool" (infix‹⊆#›50) where"A ⊆# B ⟷ (∀a. count A a ≤ count B a)"
definition subset_mset :: "'a multiset ==> 'a multiset ==> bool" (infix‹⊂#›50) where"A ⊂# B ⟷ A ⊆# B ∧ A ≠ B"
abbreviation (input) supseteq_mset :: "'a multiset ==> 'a multiset ==> bool" (infix‹??#›50) where"supseteq_mset A B ≡ B ⊆# A"
abbreviation (input) supset_mset :: "'a multiset ==> 'a multiset ==> bool" (infix‹🪙#›50) where"supset_mset A B ≡ B ⊂# A"
notation (input)
subseteq_mset (infix‹≤#›50) and
supseteq_mset (infix‹≥#›50)
notation (ASCII)
subseteq_mset (infix‹<=#›50) and
subset_mset (infix‹<#\›50) and
supseteq_mset (infix‹>=#›50) and
supset_mset (infix‹>#›50)
global_interpretation subset_mset: ordering ‹(⊆#)›‹(⊂#)› by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order.trans order.antisym)
interpretation subset_mset: ordered_ab_semigroup_add_imp_le ‹(+)›‹(-)›‹(⊆#)›‹(⊂#)› by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order_trans antisym)
― ‹FIXME: avoid junk stemming from type class interpretation›
interpretation subset_mset: ordered_ab_semigroup_monoid_add_imp_le "(+)"0"(-)""(⊆#)""(⊂#)" by standard
― ‹FIXME: avoid junk stemming from type class interpretation›
lemma mset_subset_eqI: "(∧a. count A a ≤ count B a) ==> A ⊆# B" by (simp add: subseteq_mset_def)
lemma mset_subset_eq_count: "A ⊆# B ==> count A a ≤ count B a" by (simp add: subseteq_mset_def)
lemma mset_subset_eq_exists_conv: "(A::'a multiset) ⊆# B ⟷ (∃C. B = A + C)" unfolding subseteq_mset_def by (metis add_diff_cancel_left' count_diff count_union le_Suc_ex le_add_same_cancel1 multiset_eq_iff zero_le)
interpretation subset_mset: ordered_cancel_comm_monoid_diff "(+)"0"(⊆#)""(⊂#)""(-)" by standard (simp, fact mset_subset_eq_exists_conv)
― ‹FIXME: avoid junk stemming from type class interpretation›
lemma mset_subset_eq_mono_add_right_cancel: "(A::'a multiset) + C ⊆# B + C ⟷ A ⊆# B" by (fact subset_mset.add_le_cancel_right)
lemma mset_subset_eq_mono_add_left_cancel: "C + (A::'a multiset) ⊆# C + B ⟷ A ⊆# B" by (fact subset_mset.add_le_cancel_left)
lemma mset_subset_eq_mono_add: "(A::'a multiset) ⊆# B ==> C ⊆# D ==> A + C ⊆# B + D" by (fact subset_mset.add_mono)
lemma mset_subset_eq_add_left: "(A::'a multiset) ⊆# A + B" by simp
lemma mset_subset_eq_add_right: "B ⊆# (A::'a multiset) + B" by simp
lemma single_subset_iff [simp]: "{#a#} ⊆# M ⟷ a ∈# M" by (auto simp add: subseteq_mset_def Suc_le_eq)
lemma mset_subset_eq_single: "a ∈# B ==> {#a#} ⊆# B" by simp
lemma mset_subset_eq_add_mset_cancel: ‹add_mset a A ⊆# add_mset a B ⟷ A ⊆# B› unfolding add_mset_add_single[of _ A] add_mset_add_single[of _ B] by (rule mset_subset_eq_mono_add_right_cancel)
lemma multiset_diff_union_assoc: fixes A B C D :: "'a multiset" shows"C ⊆# B ==> A + B - C = A + (B - C)" by (fact subset_mset.diff_add_assoc)
lemma mset_subset_eq_multiset_union_diff_commute: fixes A B C D :: "'a multiset" shows"B ⊆# A ==> A - B + C = A + C - B" by (fact subset_mset.add_diff_assoc2)
lemma diff_subset_eq_self[simp]: "(M::'a multiset) - N ⊆# M" by (simp add: subseteq_mset_def)
lemma mset_subset_eqD: assumes"A ⊆# B"and"x ∈# A" shows"x ∈# B" proof - from‹x ∈# A›have"count A x > 0"by simp alsofrom‹A ⊆# B›have"count A x ≤ count B x" by (simp add: subseteq_mset_def) finallyshow ?thesis by simp qed
lemma mset_subsetD: "A ⊂# B ==> x ∈# A ==> x ∈# B" by (auto intro: mset_subset_eqD [of A])
lemma set_mset_mono: "A ⊆# B ==> set_mset A ⊆ set_mset B" by (metis mset_subset_eqD subsetI)
lemma mset_subset_eq_insertD: assumes"add_mset x A ⊆# B" shows"x ∈# B ∧ A ⊂# B" proof show"x ∈# B" using assms by (simp add: mset_subset_eqD) have"A ⊆# add_mset x A" by (metis (no_types) add_mset_add_single mset_subset_eq_add_left) thenhave"A ⊂# add_mset x A" by (meson multi_self_add_other_not_self subset_mset.le_imp_less_or_eq) thenshow"A ⊂# B" using assms subset_mset.strict_trans2 by blast qed
lemma mset_subset_insertD: "add_mset x A ⊂# B ==> x ∈# B ∧ A ⊂# B" by (rule mset_subset_eq_insertD) simp
lemma mset_subset_of_empty[simp]: "A ⊂# {#} ⟷ False" by (simp only: subset_mset.not_less_zero)
lemma empty_subset_add_mset[simp]: "{#} ⊂# add_mset x M" by (auto intro: subset_mset.gr_zeroI)
lemma empty_le: "{#} ⊆# A" by (fact subset_mset.zero_le)
lemma insert_subset_eq_iff: "add_mset a A ⊆# B ⟷ a ∈# B ∧ A ⊆# B - {#a#}" using mset_subset_eq_insertD subset_mset.le_diff_conv2 by fastforce
lemma insert_union_subset_iff: "add_mset a A ⊂# B ⟷ a ∈# B ∧ A ⊂# B - {#a#}" by (auto simp add: insert_subset_eq_iff subset_mset_def)
lemma subset_eq_diff_conv: "A - C ⊆# B ⟷ A ⊆# B + C" by (simp add: subseteq_mset_def le_diff_conv)
lemma multi_psub_of_add_self [simp]: "A ⊂# add_mset x A" by (auto simp: subset_mset_def subseteq_mset_def)
lemma multi_psub_self: "A ⊂# A = False" by simp
lemma mset_subset_add_mset [simp]: "add_mset x N ⊂# add_mset x M ⟷ N ⊂# M" unfolding add_mset_add_single[of _ N] add_mset_add_single[of _ M] by (fact subset_mset.add_less_cancel_right)
lemma mset_subset_diff_self: "c ∈# B ==> B - {#c#} ⊂# B" by (auto simp: subset_mset_def elim: mset_add)
lemma Diff_eq_empty_iff_mset: "A - B = {#} ⟷ A ⊆# B" by (auto simp: multiset_eq_iff subseteq_mset_def)
lemma add_mset_subseteq_single_iff[iff]: "add_mset a M ⊆# {#b#} ⟷ M = {#} ∧ a = b" proof assume A: "add_mset a M ⊆# {#b#}" thenhave‹a = b› by (auto dest: mset_subset_eq_insertD) thenshow"M={#} ∧ a=b" using A by (simp add: mset_subset_eq_add_mset_cancel) qed simp
lemma nonempty_subseteq_mset_eq_single: "M ≠ {#} ==> M ⊆# {#x#} ==> M = {#x#}" by (cases M) (metis single_is_union subset_mset.less_eqE)
lemma nonempty_subseteq_mset_iff_single: "(M ≠ {#} ∧ M ⊆# {#x#} ∧ P) ⟷ M = {#x#} ∧ P" by (cases M) (metis empty_not_add_mset nonempty_subseteq_mset_eq_single subset_mset.order_refl)
subsubsection‹Intersection and bounded union›
definition inter_mset :: ‹'a multiset ==> 'a multiset ==> 'a multiset› (infixl‹∩#›70) where‹A ∩# B = A - (A - B)›
lemma count_inter_mset [simp]: ‹count (A ∩# B) x = min (count A x) (count B x)› by (simp add: inter_mset_def)
(*global_interpretation subset_mset: semilattice_order \<open>(\<inter>#)\<close> \<open>(\<subseteq>#)\<close> \<open>(\<subset>#)\<close>
by standard (simp_all add: multiset_eq_iff subseteq_mset_def subset_mset_def min_def)*)
interpretation subset_mset: semilattice_inf ‹(∩#)›‹(⊆#)›‹(⊂#)› by standard (simp_all add: multiset_eq_iff subseteq_mset_def)
― ‹FIXME: avoid junk stemming from type class interpretation›
definition union_mset :: ‹'a multiset ==> 'a multiset ==> 'a multiset› (infixl‹∪#›70) where‹A ∪# B = A + (B - A)›
lemma count_union_mset [simp]: ‹count (A ∪# B) x = max (count A x) (count B x)› by (simp add: union_mset_def)
global_interpretation subset_mset: semilattice_neutr_order ‹(∪#)›‹{#}›‹(🪙#)›‹(??#)› proof show"∧a b. (b ⊆# a) = (a = a ∪# b)" by (simp add: Diff_eq_empty_iff_mset union_mset_def) show"∧a b. (b ⊂# a) = (a = a ∪# b ∧ a ≠ b)" by (metis Diff_eq_empty_iff_mset add_cancel_left_right subset_mset_def union_mset_def) qed (auto simp: multiset_eqI union_mset_def)
interpretation subset_mset: semilattice_sup ‹(∪#)›‹(⊆#)›‹(⊂#)› proof - have [simp]: "m ≤ n ==> q ≤ n ==> m + (q - m) ≤ n"for m n q :: nat by arith show"class.semilattice_sup (∪#) (⊆#) (⊂#)" by standard (auto simp add: union_mset_def subseteq_mset_def) qed ― ‹FIXME: avoid junk stemming from type class interpretation›
interpretation subset_mset: bounded_lattice_bot "(∩#)""(⊆#)""(⊂#)" "(∪#)""{#}" by standard auto
― ‹FIXME: avoid junk stemming from type class interpretation›
subsubsection‹Additional intersection facts›
lemma set_mset_inter [simp]: "set_mset (A ∩# B) = set_mset A ∩ set_mset B" by (simp only: set_mset_def) auto
lemma diff_intersect_left_idem [simp]: "M - M ∩# N = M - N" by (simp add: multiset_eq_iff min_def)
lemma diff_intersect_right_idem [simp]: "M - N ∩# M = M - N" by (simp add: multiset_eq_iff min_def)
lemma multiset_inter_single[simp]: "a ≠ b ==> {#a#} ∩# {#b#} = {#}" by (rule multiset_eqI) auto
lemma multiset_union_diff_commute: assumes"B ∩# C = {#}" shows"A + B - C = A - C + B" proof (rule multiset_eqI) fix x from assms have"min (count B x) (count C x) = 0" by (auto simp add: multiset_eq_iff) thenhave"count B x = 0 ∨ count C x = 0" unfolding min_def by (auto split: if_splits) thenshow"count (A + B - C) x = count (A - C + B) x" by auto qed
lemma disjunct_not_in: "A ∩# B = {#} ⟷ (∀a. a ∉# A ∨ a ∉# B)" by (metis disjoint_iff set_mset_eq_empty_iff set_mset_inter)
lemma inter_mset_empty_distrib_right: "A ∩# (B + C) = {#} ⟷ A ∩# B = {#} ∧ A ∩# C = {#}" by (meson disjunct_not_in union_iff)
lemma inter_mset_empty_distrib_left: "(A + B) ∩# C = {#} ⟷ A ∩# C = {#} ∧ B ∩# C = {#}" by (meson disjunct_not_in union_iff)
lemma add_mset_inter_add_mset [simp]: "add_mset a A ∩# add_mset a B = add_mset a (A ∩# B)" by (rule multiset_eqI) simp
lemma add_mset_disjoint [simp]: "add_mset a A ∩# B = {#} ⟷ a ∉# B ∧ A ∩# B = {#}" "{#} = add_mset a A ∩# B ⟷ a ∉# B ∧ {#} = A ∩# B" by (auto simp: disjunct_not_in)
lemma disjoint_add_mset [simp]: "B ∩# add_mset a A = {#} ⟷ a ∉# B ∧ B ∩# A = {#}" "{#} = A ∩# add_mset b B ⟷ b ∉# A ∧ {#} = A ∩# B" by (auto simp: disjunct_not_in)
lemma inter_add_left1: "¬ x ∈# N ==> (add_mset x M) ∩# N = M ∩# N" by (simp add: multiset_eq_iff not_in_iff)
lemma inter_add_left2: "x ∈# N ==> (add_mset x M) ∩# N = add_mset x (M ∩# (N - {#x#}))" by (auto simp add: multiset_eq_iff elim: mset_add)
lemma inter_add_right1: "¬ x ∈# N ==> N ∩# (add_mset x M) = N ∩# M" by (simp add: multiset_eq_iff not_in_iff)
lemma inter_add_right2: "x ∈# N ==> N ∩# (add_mset x M) = add_mset x ((N - {#x#}) ∩# M)" by (auto simp add: multiset_eq_iff elim: mset_add)
lemma disjunct_set_mset_diff: assumes"M ∩# N = {#}" shows"set_mset (M - N) = set_mset M" proof (rule set_eqI) fix a from assms have"a ∉# M ∨ a ∉# N" by (simp add: disjunct_not_in) thenshow"a ∈# M - N ⟷ a ∈# M" by (auto dest: in_diffD) (simp add: in_diff_count not_in_iff) qed
lemma at_most_one_mset_mset_diff: assumes"a ∉# M - {#a#}" shows"set_mset (M - {#a#}) = set_mset M - {a}" using assms by (auto simp add: not_in_iff in_diff_count set_eq_iff)
lemma more_than_one_mset_mset_diff: assumes"a ∈# M - {#a#}" shows"set_mset (M - {#a#}) = set_mset M" proof (rule set_eqI) fix b have"Suc 0 < count M b ==> count M b > 0"by arith thenshow"b ∈# M - {#a#} ⟷ b ∈# M" using assms by (auto simp add: in_diff_count) qed
lemma inter_iff: "a ∈# A ∩# B ⟷ a ∈# A ∧ a ∈# B" by simp
lemma inter_union_distrib_left: "A ∩# B + C = (A + C) ∩# (B + C)" by (simp add: multiset_eq_iff min_add_distrib_left)
lemma inter_union_distrib_right: "C + A ∩# B = (C + A) ∩# (C + B)" using inter_union_distrib_left [of A B C] by (simp add: ac_simps)
lemma inter_subset_eq_union: "A ∩# B ⊆# A + B" by (auto simp add: subseteq_mset_def)
subsubsection‹Additional bounded union facts›
lemma set_mset_sup [simp]: ‹set_mset (A ∪# B) = set_mset A ∪ set_mset B› by (simp only: set_mset_def) (auto simp add: less_max_iff_disj)
lemma sup_union_left1 [simp]: "¬ x ∈# N ==> (add_mset x M) ∪# N = add_mset x (M ∪# N)" by (simp add: multiset_eq_iff not_in_iff)
lemma sup_union_left2: "x ∈# N ==> (add_mset x M) ∪# N = add_mset x (M ∪# (N - {#x#}))" by (simp add: multiset_eq_iff)
lemma sup_union_right1 [simp]: "¬ x ∈# N ==> N ∪# (add_mset x M) = add_mset x (N ∪# M)" by (simp add: multiset_eq_iff not_in_iff)
lemma sup_union_right2: "x ∈# N ==> N ∪# (add_mset x M) = add_mset x ((N - {#x#}) ∪# M)" by (simp add: multiset_eq_iff)
lemma sup_union_distrib_left: "A ∪# B + C = (A + C) ∪# (B + C)" by (simp add: multiset_eq_iff max_add_distrib_left)
lemma union_sup_distrib_right: "C + A ∪# B = (C + A) ∪# (C + B)" using sup_union_distrib_left [of A B C] by (simp add: ac_simps)
lemma union_diff_inter_eq_sup: "A + B - A ∩# B = A ∪# B" by (auto simp add: multiset_eq_iff)
lemma union_diff_sup_eq_inter: "A + B - A ∪# B = A ∩# B" by (auto simp add: multiset_eq_iff)
lemma add_mset_union: ‹add_mset a A ∪# add_mset a B = add_mset a (A ∪# B)› by (auto simp: multiset_eq_iff max_def)
subsection‹Replicate and repeat operations›
definition replicate_mset :: "nat ==> 'a ==> 'a multiset"where "replicate_mset n x = (add_mset x ^^ n) {#}"
lemma replicate_mset_0[simp]: "replicate_mset 0 x = {#}" unfolding replicate_mset_def by simp
lemma replicate_mset_Suc [simp]: "replicate_mset (Suc n) x = add_mset x (replicate_mset n x)" unfolding replicate_mset_def by (induct n) (auto intro: add.commute)
lemma count_replicate_mset[simp]: "count (replicate_mset n x) y = (if y = x then n else 0)" unfolding replicate_mset_def by (induct n) auto
lift_definition repeat_mset :: ‹nat ==> 'a multiset ==> 'a multiset› is‹λn M a. n * M a›by simp
lemma count_repeat_mset [simp]: "count (repeat_mset i A) a = i * count A a" by transfer rule
lemma repeat_mset_0 [simp]: ‹repeat_mset 0 M = {#}› by transfer simp
lemma repeat_mset_Suc [simp]: ‹repeat_mset (Suc n) M = M + repeat_mset n M› by transfer simp
lemma repeat_mset_right [simp]: "repeat_mset a (repeat_mset b A) = repeat_mset (a * b) A" by (auto simp: multiset_eq_iff left_diff_distrib')
lemma left_diff_repeat_mset_distrib': ‹repeat_mset (i - j) u = repeat_mset i u - repeat_mset j u› by (auto simp: multiset_eq_iff left_diff_distrib')
lemma left_add_mult_distrib_mset: "repeat_mset i u + (repeat_mset j u + k) = repeat_mset (i+j) u + k" by (auto simp: multiset_eq_iff add_mult_distrib)
lemma repeat_mset_distrib: "repeat_mset (m + n) A = repeat_mset m A + repeat_mset n A" by (auto simp: multiset_eq_iff Nat.add_mult_distrib)
lemma repeat_mset_distrib2[simp]: "repeat_mset n (A + B) = repeat_mset n A + repeat_mset n B" by (auto simp: multiset_eq_iff add_mult_distrib2)
lemma repeat_mset_replicate_mset[simp]: "repeat_mset n {#a#} = replicate_mset n a" by (auto simp: multiset_eq_iff)
lemma repeat_mset_distrib_add_mset[simp]: "repeat_mset n (add_mset a A) = replicate_mset n a + repeat_mset n A" by (auto simp: multiset_eq_iff)
lemma repeat_mset_empty[simp]: "repeat_mset n {#} = {#}" by transfer simp
lemma set_mset_sum: "finite A ==> set_mset (∑x∈A. f x) = (∪x∈A. set_mset (f x))" by (induction A rule: finite_induct) auto
subsubsection‹Simprocs›
lemma repeat_mset_iterate_add: ‹repeat_mset n M = iterate_add n M› unfolding iterate_add_def by (induction n) auto
lemma mset_subseteq_add_iff1: "j ≤ (i::nat) ==> (repeat_mset i u + m ⊆# repeat_mset j u + n) = (repeat_mset (i-j) u + m ⊆# n)" by (auto simp add: subseteq_mset_def nat_le_add_iff1)
lemma mset_subseteq_add_iff2: "i ≤ (j::nat) ==> (repeat_mset i u + m ⊆# repeat_mset j u + n) = (m ⊆# repeat_mset (j-i) u + n)" by (auto simp add: subseteq_mset_def nat_le_add_iff2)
lemma mset_subset_add_iff1: "j ≤ (i::nat) ==> (repeat_mset i u + m ⊂# repeat_mset j u + n) = (repeat_mset (i-j) u + m ⊂# n)" unfolding subset_mset_def repeat_mset_iterate_add by (simp add: iterate_add_eq_add_iff1 mset_subseteq_add_iff1[unfolded repeat_mset_iterate_add])
lemma mset_subset_add_iff2: "i ≤ (j::nat) ==> (repeat_mset i u + m ⊂# repeat_mset j u + n) = (m ⊂# repeat_mset (j-i) u + n)" unfolding subset_mset_def repeat_mset_iterate_add by (simp add: iterate_add_eq_add_iff2 mset_subseteq_add_iff2[unfolded repeat_mset_iterate_add])
ML_file ‹multiset_simprocs.ML›
lemma add_mset_replicate_mset_safe[cancelation_simproc_pre]: ‹NO_MATCH {#} M ==> add_mset a M = {#a#} + M› by simp
simproc_setup mseteq_cancel
("(l::'a multiset) + m = n" | "(l::'a multiset) = m + n" | "add_mset a m = n" | "m = add_mset a n" | "replicate_mset p a = n" | "m = replicate_mset p a" | "repeat_mset p m = n" | "m = repeat_mset p m") = ‹K Cancel_Simprocs.eq_cancel›
simproc_setup msetsubset_cancel
("(l::'a multiset) + m ⊂# n" | "(l::'a multiset) ⊂# m + n" | "add_mset a m ⊂# n" | "m ⊂# add_mset a n" | "replicate_mset p r ⊂# n" | "m ⊂# replicate_mset p r" | "repeat_mset p m ⊂# n" | "m ⊂# repeat_mset p m") = ‹K Multiset_Simprocs.subset_cancel_msets›
simproc_setup msetsubset_eq_cancel
("(l::'a multiset) + m ⊆# n" | "(l::'a multiset) ⊆# m + n" | "add_mset a m ⊆# n" | "m ⊆# add_mset a n" | "replicate_mset p r ⊆# n" | "m ⊆# replicate_mset p r" | "repeat_mset p m ⊆# n" | "m ⊆# repeat_mset p m") = ‹K Multiset_Simprocs.subseteq_cancel_msets›
simproc_setup msetdiff_cancel
("((l::'a multiset) + m) - n" | "(l::'a multiset) - (m + n)" | "add_mset a m - n" | "m - add_mset a n" | "replicate_mset p r - n" | "m - replicate_mset p r" | "repeat_mset p m - n" | "m - repeat_mset p m") = ‹K Cancel_Simprocs.diff_cancel›
subsubsection‹Conditionally complete lattice›
instantiation multiset :: (type) Inf begin
lift_definition Inf_multiset :: "'a multiset set ==> 'a multiset"is "λA i. if A = {} then 0 else Inf ((λf. f i) ` A)" proof - fix A :: "('a ==> nat) set" assume *: "∧f. f ∈ A ==> finite {x. 0 < f x}" show‹finite {i. 0 < (if A = {} then 0 else INF f∈A. f i)}› proof (cases "A = {}") case False thenobtain f where"f ∈ A"by blast hence"{i. Inf ((λf. f i) ` A) > 0} ⊆ {i. f i > 0}" by (auto intro: less_le_trans[OF _ cInf_lower]) moreoverfrom‹f ∈ A› * have"finite …"by simp ultimatelyhave"finite {i. Inf ((λf. f i) ` A) > 0}"by (rule finite_subset) with False show ?thesis by simp qed simp_all qed
instance ..
end
lemma Inf_multiset_empty: "Inf {} = {#}" by transfer simp_all
lemma count_Inf_multiset_nonempty: "A ≠ {} ==> count (Inf A) x = Inf ((λX. count X x) ` A)" by transfer simp_all
instantiation multiset :: (type) Sup begin
definition Sup_multiset :: "'a multiset set ==> 'a multiset"where "Sup_multiset A = (if A ≠ {} ∧ subset_mset.bdd_above A then Abs_multiset (λi. Sup ((λX. count X i) ` A)) else {#})"
lemma Sup_multiset_empty: "Sup {} = {#}" by (simp add: Sup_multiset_def)
lemma Sup_multiset_unbounded: "¬ subset_mset.bdd_above A ==> Sup A = {#}" by (simp add: Sup_multiset_def)
instance ..
end
lemma bdd_above_multiset_imp_bdd_above_count: assumes"subset_mset.bdd_above (A :: 'a multiset set)" shows"bdd_above ((λX. count X x) ` A)" proof - from assms obtain Y where Y: "∀X∈A. X ⊆# Y" by (meson subset_mset.bdd_above.E) hence"count X x ≤ count Y x"if"X ∈ A"for X using that by (auto intro: mset_subset_eq_count) thus ?thesis by (intro bdd_aboveI[of _ "count Y x"]) auto qed
lemma bdd_above_multiset_imp_finite_support: assumes"A ≠ {}""subset_mset.bdd_above (A :: 'a multiset set)" shows"finite (∪X∈A. {x. count X x > 0})" proof - from assms obtain Y where Y: "∀X∈A. X ⊆# Y" by (meson subset_mset.bdd_above.E) hence"count X x ≤ count Y x"if"X ∈ A"for X x using that by (auto intro: mset_subset_eq_count) hence"(∪X∈A. {x. count X x > 0}) ⊆ {x. count Y x > 0}" by safe (erule less_le_trans) moreoverhave"finite …"by simp ultimatelyshow ?thesis by (rule finite_subset) qed
lemma Sup_multiset_in_multiset: ‹finite {i. 0 < (SUP M∈A. count M i)}› if‹A ≠ {}›‹subset_mset.bdd_above A› proof - have"{i. Sup ((λX. count X i) ` A) > 0} ⊆ (∪X∈A. {i. 0 < count X i})" proof safe fix i assume pos: "(SUP X∈A. count X i) > 0" show"i ∈ (∪X∈A. {i. 0 < count X i})" proof (rule ccontr) assume"i ∉ (∪X∈A. {i. 0 < count X i})" hence"∀X∈A. count X i ≤ 0"by (auto simp: count_eq_zero_iff) with that have"(SUP X∈A. count X i) ≤ 0" by (intro cSup_least bdd_above_multiset_imp_bdd_above_count) auto with pos show False by simp qed qed moreoverfrom that have"finite …" by (rule bdd_above_multiset_imp_finite_support) ultimatelyshow"finite {i. Sup ((λX. count X i) ` A) > 0}" by (rule finite_subset) qed
lemma count_Sup_multiset_nonempty: ‹count (Sup A) x = (SUP X∈A. count X x)› if‹A ≠ {}›‹subset_mset.bdd_above A› using that by (simp add: Sup_multiset_def Sup_multiset_in_multiset count_Abs_multiset)
interpretation subset_mset: conditionally_complete_lattice Inf Sup "(∩#)""(⊆#)""(⊂#)""(∪#)" proof fix X :: "'a multiset"and A assume"X ∈ A" show"Inf A ⊆# X" by (metis ‹X ∈ A› count_Inf_multiset_nonempty empty_iff image_eqI mset_subset_eqI wellorder_Inf_le1) next fix X :: "'a multiset"and A assume nonempty: "A ≠ {}"and le: "∧Y. Y ∈ A ==> X ⊆# Y" show"X ⊆# Inf A" proof (rule mset_subset_eqI) fix x from nonempty have"count X x ≤ (INF X∈A. count X x)" by (intro cInf_greatest) (auto intro: mset_subset_eq_count le) alsofrom nonempty have"… = count (Inf A) x"by (simp add: count_Inf_multiset_nonempty) finallyshow"count X x ≤ count (Inf A) x" . qed next fix X :: "'a multiset"and A assume X: "X ∈ A"and bdd: "subset_mset.bdd_above A" show"X ⊆# Sup A" proof (rule mset_subset_eqI) fix x from X have"A ≠ {}"by auto have"count X x ≤ (SUP X∈A. count X x)" by (intro cSUP_upper X bdd_above_multiset_imp_bdd_above_count bdd) alsofrom count_Sup_multiset_nonempty[OF ‹A ≠ {}› bdd] have"(SUP X∈A. count X x) = count (Sup A) x"by simp finallyshow"count X x ≤ count (Sup A) x" . qed next fix X :: "'a multiset"and A assume nonempty: "A ≠ {}"and ge: "∧Y. Y ∈ A ==> Y ⊆# X" from ge have bdd: "subset_mset.bdd_above A" by blast show"Sup A ⊆# X" proof (rule mset_subset_eqI) fix x from count_Sup_multiset_nonempty[OF ‹A ≠ {}› bdd] have"count (Sup A) x = (SUP X∈A. count X x)" . alsofrom nonempty have"…≤ count X x" by (intro cSup_least) (auto intro: mset_subset_eq_count ge) finallyshow"count (Sup A) x ≤ count X x" . qed qed ― ‹FIXME: avoid junk stemming from type class interpretation›
lemma set_mset_Inf: assumes"A ≠ {}" shows"set_mset (Inf A) = (∩X∈A. set_mset X)" proof safe fix x X assume"x ∈# Inf A""X ∈ A" hence nonempty: "A ≠ {}"by (auto simp: Inf_multiset_empty) from‹x ∈# Inf A›have"{#x#} ⊆# Inf A"by auto alsofrom‹X ∈ A›have"…⊆# X"by (rule subset_mset.cInf_lower) simp_all finallyshow"x ∈# X"by simp next fix x assume x: "x ∈ (∩X∈A. set_mset X)" hence"{#x#} ⊆# X"if"X ∈ A"for X using that by auto from assms and this have"{#x#} ⊆# Inf A"by (rule subset_mset.cInf_greatest) thus"x ∈# Inf A"by simp qed
lemma in_Inf_multiset_iff: assumes"A ≠ {}" shows"x ∈# Inf A ⟷ (∀X∈A. x ∈# X)" proof - from assms have"set_mset (Inf A) = (∩X∈A. set_mset X)"by (rule set_mset_Inf) alsohave"x ∈…⟷ (∀X∈A. x ∈# X)"by simp finallyshow ?thesis . qed
lemma in_Inf_multisetD: "x ∈# Inf A ==> X ∈ A ==> x ∈# X" by (subst (asm) in_Inf_multiset_iff) auto
lemma set_mset_Sup: assumes"subset_mset.bdd_above A" shows"set_mset (Sup A) = (∪X∈A. set_mset X)" proof safe fix x assume"x ∈# Sup A" hence nonempty: "A ≠ {}"by (auto simp: Sup_multiset_empty) show"x ∈ (∪X∈A. set_mset X)" proof (rule ccontr) assume x: "x ∉ (∪X∈A. set_mset X)" have"count X x ≤ count (Sup A) x"if"X ∈ A"for X x using that by (intro mset_subset_eq_count subset_mset.cSup_upper assms) with x have"X ⊆# Sup A - {#x#}"if"X ∈ A"for X using that by (auto simp: subseteq_mset_def algebra_simps not_in_iff) hence"Sup A ⊆# Sup A - {#x#}"by (intro subset_mset.cSup_least nonempty) with‹x ∈# Sup A›show False using mset_subset_diff_self by fastforce qed next fix x X assume"x ∈ set_mset X""X ∈ A" hence"{#x#} ⊆# X"by auto alsohave"X ⊆# Sup A"by (intro subset_mset.cSup_upper ‹X ∈ A› assms) finallyshow"x ∈ set_mset (Sup A)"by simp qed
lemma in_Sup_multiset_iff: assumes"subset_mset.bdd_above A" shows"x ∈# Sup A ⟷ (∃X∈A. x ∈# X)" by (simp add: assms set_mset_Sup)
lemma in_Sup_multisetD: assumes"x ∈# Sup A" shows"∃X∈A. x ∈# X" using Sup_multiset_unbounded assms in_Sup_multiset_iff by fastforce
interpretation subset_mset: distrib_lattice "(∩#)""(⊆#)""(⊂#)""(∪#)" proof fix A B C :: "'a multiset" show"A ∪# (B ∩# C) = A ∪# B ∩# (A ∪# C)" by (intro multiset_eqI) simp_all qed ― ‹FIXME: avoid junk stemming from type class interpretation›
subsubsection‹Filter (with comprehension syntax)›
text‹Multiset comprehension›
lift_definition filter_mset :: "('a ==> bool) ==> 'a multiset ==> 'a multiset" is"λP M. λx. if P x then M x else 0" by (rule filter_preserves_multiset)
lemma count_filter_mset [simp]: "count (filter_mset P M) a = (if P a then count M a else 0)" by (simp add: filter_mset.rep_eq)
lemma set_mset_filter [simp]: "set_mset (filter_mset P M) = {a ∈ set_mset M. P a}" by (simp only: set_eq_iff count_greater_zero_iff [symmetric] count_filter_mset) simp
lemma filter_empty_mset [simp]: "filter_mset P {#} = {#}" by (rule multiset_eqI) simp
lemma filter_single_mset: "filter_mset P {#x#} = (if P x then {#x#} else {#})" by (rule multiset_eqI) simp
lemma filter_union_mset [simp]: "filter_mset P (M + N) = filter_mset P M + filter_mset P N" by (rule multiset_eqI) simp
lemma filter_diff_mset [simp]: "filter_mset P (M - N) = filter_mset P M - filter_mset P N" by (rule multiset_eqI) simp
lemma filter_inter_mset [simp]: "filter_mset P (M ∩# N) = filter_mset P M ∩# filter_mset P N" by (rule multiset_eqI) simp
lemma filter_sup_mset[simp]: "filter_mset P (A ∪# B) = filter_mset P A ∪# filter_mset P B" by (rule multiset_eqI) simp
lemma filter_mset_add_mset [simp]: "filter_mset P (add_mset x A) = (if P x then add_mset x (filter_mset P A) else filter_mset P A)" by (auto simp: multiset_eq_iff)
lemma multiset_filter_subset[simp]: "filter_mset f M ⊆# M" by (simp add: mset_subset_eqI)
lemma filter_mset_mono_strong: assumes"A ⊆# B""∧x. x ∈# A ==> P x ==> Q x" shows"filter_mset P A ⊆# filter_mset Q B" by (rule mset_subset_eqI) (insert assms, auto simp: mset_subset_eq_count count_eq_zero_iff)
(* TODO: rename to filter_mset_mono_strong *) lemma multiset_filter_mono: assumes"A ⊆# B" shows"filter_mset f A ⊆# filter_mset f B" using filter_mset_mono_strong[OF ‹A ⊆# B›] .
lemma filter_mset_eq_conv: "filter_mset P M = N ⟷ N ⊆# M ∧ (∀b∈#N. P b) ∧ (∀a∈#M - N. ¬ P a)" (is"?P ⟷ ?Q") proof assume ?P thenshow ?Q by auto (simp add: multiset_eq_iff in_diff_count) next assume ?Q thenobtain Q where M: "M = N + Q" by (auto simp add: mset_subset_eq_exists_conv) thenhave MN: "M - N = Q"by simp show ?P proof (rule multiset_eqI) fix a from‹?Q› MN have *: "¬ P a ==> a ∉# N""P a ==> a ∉# Q" by auto show"count (filter_mset P M) a = count N a" proof (cases "a ∈# M") case True with * show ?thesis by (simp add: not_in_iff M) next case False thenhave"count M a = 0" by (simp add: not_in_iff) with M show ?thesis by simp qed qed qed
lemma filter_mset_eq_mempty_iff[simp]: "filter_mset P A = {#} ⟷ (∀x. x ∈# A ⟶¬ P x)" by (auto simp: multiset_eq_iff count_eq_zero_iff)
lemma filter_filter_mset: "filter_mset P (filter_mset Q M) = {#x ∈# M. Q x ∧ P x#}" by (auto simp: multiset_eq_iff)
lemma
filter_mset_True[simp]: "{#y ∈# M. True#} = M"and
filter_mset_False[simp]: "{#y ∈# M. False#} = {#}" by (auto simp: multiset_eq_iff)
lemma filter_mset_cong0: assumes"∧x. x ∈# M ==> f x ⟷ g x" shows"filter_mset f M = filter_mset g M" proof (rule subset_mset.antisym; unfold subseteq_mset_def; rule allI) fix x show"count (filter_mset f M) x ≤ count (filter_mset g M) x" using assms by (cases "x ∈# M") (simp_all add: not_in_iff) next fix x show"count (filter_mset g M) x ≤ count (filter_mset f M) x" using assms by (cases "x ∈# M") (simp_all add: not_in_iff) qed
lemma filter_mset_cong: assumes"M = M'"and"∧x. x ∈# M' ==> f x ⟷ g x" shows"filter_mset f M = filter_mset g M'" unfolding‹M = M'› using assms by (auto intro: filter_mset_cong0)
lemma filter_eq_replicate_mset: "{#y ∈# D. y = x#} = replicate_mset (count D x) x" by (induct D) (simp add: multiset_eqI)
subsubsection‹Size›
definition wcount where"wcount f M = (λx. count M x * Suc (f x))"
lemma wcount_union: "wcount f (M + N) a = wcount f M a + wcount f N a" by (auto simp: wcount_def add_mult_distrib)
lemma wcount_add_mset: "wcount f (add_mset x M) a = (if x = a then Suc (f a) else 0) + wcount f M a" unfolding add_mset_add_single[of _ M] wcount_union by (auto simp: wcount_def)
definition size_multiset :: "('a ==> nat) ==> 'a multiset ==> nat"where "size_multiset f M = sum (wcount f M) (set_mset M)"
lemma sum_wcount_Int: "finite A ==> sum (wcount f N) (A ∩ set_mset N) = sum (wcount f N) A" by (induct rule: finite_induct)
(simp_all add: Int_insert_left wcount_def count_eq_zero_iff)
lemma size_multiset_union [simp]: "size_multiset f (M + N::'a multiset) = size_multiset f M + size_multiset f N" apply (simp add: size_multiset_def sum_Un_nat sum.distrib sum_wcount_Int wcount_union) by (metis add_implies_diff finite_set_mset inf.commute sum_wcount_Int)
lemma size_multiset_add_mset [simp]: "size_multiset f (add_mset a M) = Suc (f a) + size_multiset f M" by (metis add.commute add_mset_add_single size_multiset_single size_multiset_union)
lemma size_add_mset [simp]: "size (add_mset a A) = Suc (size A)" by (simp add: size_multiset_overloaded_def wcount_add_mset)
lemma size_union [simp]: "size (M + N::'a multiset) = size M + size N" by (auto simp add: size_multiset_overloaded_def)
lemma size_multiset_eq_0_iff_empty [iff]: "size_multiset f M = 0 ⟷ M = {#}" by (auto simp add: size_multiset_eq count_eq_zero_iff)
lemma size_eq_0_iff_empty [iff]: "(size M = 0) = (M = {#})" by (auto simp add: size_multiset_overloaded_def)
lemma size_eq_Suc_imp_elem: "size M = Suc n ==>∃a. a ∈# M" using all_not_in_conv by fastforce
lemma size_eq_Suc_imp_eq_union: assumes"size M = Suc n" shows"∃a N. M = add_mset a N" by (metis assms insert_DiffM size_eq_Suc_imp_elem)
lemma size_mset_mono: fixes A B :: "'a multiset" assumes"A ⊆# B" shows"size A ≤ size B" proof - from assms[unfolded mset_subset_eq_exists_conv] obtain C where B: "B = A + C"by auto show ?thesis unfolding B by (induct C) auto qed
lemma size_filter_mset_lesseq[simp]: "size (filter_mset f M) ≤ size M" by (rule size_mset_mono[OF multiset_filter_subset])
lemma size_lt_imp_ex_count_lt: "size M < size N ==>∃x ∈# N. count M x < count N x" by (metis count_eq_zero_iff leD not_le_imp_less not_less_zero size_mset_mono subseteq_mset_def)
subsection‹Induction and case splits›
theorem multiset_induct [case_names empty add, induct type: multiset]: assumes empty: "P {#}" assumes add: "∧x M. P M ==> P (add_mset x M)" shows"P M" proof (induct "size M" arbitrary: M) case0thus"P M"by (simp add: empty) next case (Suc k) obtain N x where"M = add_mset x N" using‹Suc k = size M› [symmetric] using size_eq_Suc_imp_eq_union by fast with Suc add show"P M"by simp qed
lemma multiset_induct_min[case_names empty add]: fixes M :: "'a::linorder multiset" assumes
empty: "P {#}"and
add: "∧x M. P M ==> (∀y ∈# M. y ≥ x) ==> P (add_mset x M)" shows"P M" proof (induct "size M" arbitrary: M) case (Suc k) note ih = this(1) and Sk_eq_sz_M = this(2)
let ?y = "Min_mset M" let ?N = "M - {#?y#}"
have M: "M = add_mset ?y ?N" by (metis Min_in Sk_eq_sz_M finite_set_mset insert_DiffM lessI not_less_zero
set_mset_eq_empty_iff size_empty) show ?case by (subst M, rule add, rule ih, metis M Sk_eq_sz_M nat.inject size_add_mset,
meson Min_le finite_set_mset in_diffD) qed (simp add: empty)
lemma multiset_induct_max[case_names empty add]: fixes M :: "'a::linorder multiset" assumes
empty: "P {#}"and
add: "∧x M. P M ==> (∀y ∈# M. y ≤ x) ==> P (add_mset x M)" shows"P M" proof (induct "size M" arbitrary: M) case (Suc k) note ih = this(1) and Sk_eq_sz_M = this(2)
let ?y = "Max_mset M" let ?N = "M - {#?y#}"
have M: "M = add_mset ?y ?N" by (metis Max_in Sk_eq_sz_M finite_set_mset insert_DiffM lessI not_less_zero
set_mset_eq_empty_iff size_empty) show ?case by (subst M, rule add, rule ih, metis M Sk_eq_sz_M nat.inject size_add_mset,
meson Max_ge finite_set_mset in_diffD) qed (simp add: empty)
lemma multi_nonempty_split: "M ≠ {#} ==>∃A a. M = add_mset a A" by (induct M) auto
lemma multiset_cases [cases type]: obtains (empty) "M = {#}" | (add) x N where"M = add_mset x N" by (induct M) simp_all
lemma multi_drop_mem_not_eq: "c ∈# B ==> B - {#c#} ≠ B" by (cases "B = {#}") (auto dest: multi_member_split)
lemma union_filter_mset_complement[simp]: "∀x. P x = (¬ Q x) ==> filter_mset P M + filter_mset Q M = M" by (subst multiset_eq_iff) auto
lemma multiset_partition: "M = {#x ∈# M. P x#} + {#x ∈# M. ¬ P x#}" by simp
lemma mset_subset_size: "A ⊂# B ==> size A < size B" proof (induct A arbitrary: B) case empty thenshow ?case using nonempty_has_size by auto next case (add x A) have"add_mset x A ⊆# B" by (meson add.prems subset_mset_def) thenshow ?case using add.prems subset_mset.less_eqE by fastforce qed
lemma size_1_singleton_mset: "size M = 1 ==>∃a. M = {#a#}" by (cases M) auto
lemma set_mset_subset_singletonD: assumes"set_mset A ⊆ {x}" shows"A = replicate_mset (size A) x" using assms by (induction A) auto
lemma count_conv_size_mset: "count A x = size (filter_mset (λy. y = x) A)" by (induction A) auto
lemma size_conv_count_bool_mset: "size A = count A True + count A False" by (induction A) auto
subsubsection‹Strong induction and subset induction for multisets›
text‹Well-foundedness of strict subset relation›
lemma wf_subset_mset_rel: "wf {(M, N :: 'a multiset). M ⊂# N}" using mset_subset_size wfp_def wfp_if_convertible_to_nat by blast
lemma wfp_subset_mset[simp]: "wfp (⊂#)" by (rule wf_subset_mset_rel[to_pred])
lemma full_multiset_induct [case_names less]: assumes ih: "∧B. ∀(A::'a multiset). A ⊂# B ⟶ P A ==> P B" shows"P B" apply (rule wf_subset_mset_rel [THEN wf_induct]) apply (rule ih, auto) done
lemma multi_subset_induct [consumes 2, case_names empty add]: assumes"F ⊆# A" and empty: "P {#}" and insert: "∧a F. a ∈# A ==> P F ==> P (add_mset a F)" shows"P F" proof - from‹F ⊆# A› show ?thesis proof (induct F) show"P {#}"by fact next fix x F assume P: "F ⊆# A ==> P F"and i: "add_mset x F ⊆# A" show"P (add_mset x F)" proof (rule insert) from i show"x ∈# A"by (auto dest: mset_subset_eq_insertD) from i have"F ⊆# A"by (auto dest: mset_subset_eq_insertD) with P show"P F" . qed qed qed
subsection‹Least and greatest elements›
contextbegin
qualified lemma assumes "M ≠ {#}"and "transp_on (set_mset M) R"and "totalp_on (set_mset M) R" shows
bex_least_element: "(∃l ∈# M. ∀x ∈# M. x ≠ l ⟶ R l x)"and
bex_greatest_element: "(∃g ∈# M. ∀x ∈# M. x ≠ g ⟶ R x g)" using assms by (auto intro: Finite_Set.bex_least_element Finite_Set.bex_greatest_element)
end
subsection‹The fold combinator›
definition fold_mset :: "('a ==> 'b ==> 'b) ==> 'b ==> 'a multiset ==> 'b" where "fold_mset f s M = Finite_Set.fold (λx. f x ^^ count M x) s (set_mset M)"
lemma fold_mset_empty [simp]: "fold_mset f s {#} = s" by (simp add: fold_mset_def)
lemma fold_mset_single [simp]: "fold_mset f s {#x#} = f x s" by (simp add: fold_mset_def)
context comp_fun_commute begin
lemma fold_mset_add_mset [simp]: "fold_mset f s (add_mset x M) = f x (fold_mset f s M)" proof - interpret mset: comp_fun_commute "λy. f y ^^ count M y" by (fact comp_fun_commute_funpow) interpret mset_union: comp_fun_commute "λy. f y ^^ count (add_mset x M) y" by (fact comp_fun_commute_funpow) show ?thesis proof (cases "x ∈ set_mset M") case False thenhave *: "count (add_mset x M) x = 1" by (simp add: not_in_iff) from False have"Finite_Set.fold (λy. f y ^^ count (add_mset x M) y) s (set_mset M) = Finite_Set.fold (λy. f y ^^ count M y) s (set_mset M)" by (auto intro!: Finite_Set.fold_cong comp_fun_commute_on_funpow) with False * show ?thesis by (simp add: fold_mset_def del: count_add_mset) next case True
define N where"N = set_mset M - {x}" from N_def True have *: "set_mset M = insert x N""x ∉ N""finite N"by auto thenhave"Finite_Set.fold (λy. f y ^^ count (add_mset x M) y) s N = Finite_Set.fold (λy. f y ^^ count M y) s N" by (auto intro!: Finite_Set.fold_cong comp_fun_commute_on_funpow) with * show ?thesis by (simp add: fold_mset_def del: count_add_mset) simp qed qed
lemma fold_mset_fun_left_comm: "f x (fold_mset f s M) = fold_mset f (f x s) M" by (induct M) (simp_all add: fun_left_comm)
lemma fold_mset_union [simp]: "fold_mset f s (M + N) = fold_mset f (fold_mset f s M) N" by (induct M) (simp_all add: fold_mset_fun_left_comm)
lemma fold_mset_fusion: assumes"comp_fun_commute g" and *: "∧x y. h (g x y) = f x (h y)" shows"h (fold_mset g w A) = fold_mset f (h w) A" proof - interpret comp_fun_commute g by (fact assms) from * show ?thesis by (induct A) auto qed
end
lemma union_fold_mset_add_mset: "A + B = fold_mset add_mset A B" proof - interpret comp_fun_commute add_mset by standard auto show ?thesis by (induction B) auto qed
text‹
A note on code generation: When defining some function containing a
subterm term‹fold_mset F›, code generation is not automatic. When
interpreting locale ‹left_commutative› with ‹F›, the
would be code thms for const‹fold_mset› become thms like term‹fold_mset F z {#} = z› where ‹F› is not a pattern but
contains defined symbols, i.e.\ is not a code thm. Hence a separate
constant with its own code thms needs to be introduced for ‹F›. See the image operator below. ›
subsection‹Image›
definition image_mset :: "('a ==> 'b) ==> 'a multiset ==> 'b multiset"where "image_mset f = fold_mset (add_mset ∘ f) {#}"
lemma image_mset_empty [simp]: "image_mset f {#} = {#}" by (simp add: image_mset_def)
lemma image_mset_single: "image_mset f {#x#} = {#f x#}" by (simp add: comp_fun_commute.fold_mset_add_mset comp_fun_commute_mset_image image_mset_def)
lemma image_mset_union [simp]: "image_mset f (M + N) = image_mset f M + image_mset f N" proof - interpret comp_fun_commute "add_mset ∘ f" by (fact comp_fun_commute_mset_image) show ?thesis by (induct N) (simp_all add: image_mset_def) qed
corollary image_mset_add_mset [simp]: "image_mset f (add_mset a M) = add_mset (f a) (image_mset f M)" unfolding image_mset_union add_mset_add_single[of a M] by (simp add: image_mset_single)
lemma set_image_mset [simp]: "set_mset (image_mset f M) = image f (set_mset M)" by (induct M) simp_all
lemma size_image_mset [simp]: "size (image_mset f M) = size M" by (induct M) simp_all
lemma image_mset_is_empty_iff [simp]: "image_mset f M = {#} ⟷ M = {#}" by (cases M) auto
lemma image_mset_If: "image_mset (λx. if P x then f x else g x) A = image_mset f (filter_mset P A) + image_mset g (filter_mset (λx. ¬P x) A)" by (induction A) auto
lemma filter_mset_image_mset: "filter_mset P (image_mset f A) = image_mset f (filter_mset (λx. P (f x)) A)" by (induction A) auto
lemma image_mset_Diff: assumes"B ⊆# A" shows"image_mset f (A - B) = image_mset f A - image_mset f B" proof - have"image_mset f (A - B + B) = image_mset f (A - B) + image_mset f B" by simp alsofrom assms have"A - B + B = A" by (simp add: subset_mset.diff_add) finallyshow ?thesis by simp qed
lemma minus_add_mset_if_not_in_lhs[simp]: "x ∉# A ==> A - add_mset x B = A - B" by (metis diff_intersect_left_idem inter_add_right1)
lemma image_mset_diff_if_inj: fixes f A B assumes"inj f" shows"image_mset f (A - B) = image_mset f A - image_mset f B" proof (induction B) case empty show ?case by simp next case (add x B) show ?case proof (cases "x ∈# A - B") case True
have"image_mset f (A - add_mset x B) = add_mset (f x) (image_mset f (A - add_mset x B)) - {#f x#}" unfolding add_mset_remove_trivial ..
alsohave"… = image_mset f (add_mset x (A - add_mset x B)) - {#f x#}" unfolding image_mset_add_mset ..
alsohave"… = image_mset f (add_mset x (A - B - {#x#})) - {#f x#}" unfolding add_mset_add_single[symmetric] diff_diff_add_mset ..
alsohave"… = image_mset f (A - B) - {#f x#}" unfolding insert_DiffM[OF ‹x ∈# A - B›] ..
alsohave"… = image_mset f A - image_mset f B - {#f x#}" unfolding add.IH ..
alsohave"… = image_mset f A - image_mset f (add_mset x B)" unfolding diff_diff_add_mset add_mset_add_single[symmetric] image_mset_add_mset ..
finallyshow ?thesis . next case False
hence"image_mset f (A - add_mset x B) = image_mset f (A - B)" using diff_single_trivial by fastforce
alsohave"… = image_mset f A - image_mset f B - {#f x#}" proof - have"f x ∉ f ` set_mset (A - B)" using False[folded inj_image_mem_iff[OF ‹inj f›]] .
hence"f x ∉# image_mset f (A - B)" unfolding set_image_mset .
thus ?thesis unfolding add.IH[symmetric] by (metis diff_single_trivial) qed
alsohave"… = image_mset f A - image_mset f (add_mset x B)" by simp
finallyshow ?thesis . qed qed
lemma count_image_mset: ‹count (image_mset f A) x = (∑y∈f -` {x} ∩ set_mset A. count A y)› proof (induction A) case empty thenshow ?caseby simp next case (add x A) moreoverhave *: "(if x = y then Suc n else n) = n + (if x = y then 1 else 0)"for n y by simp ultimatelyshow ?case by (auto simp: sum.distrib intro!: sum.mono_neutral_left) qed
lemma count_image_mset': ‹count (image_mset f X) y = (∑x | x ∈# X ∧ y = f x. count X x)› by (auto simp add: count_image_mset simp flip: singleton_conv2 simp add: Collect_conj_eq ac_simps)
lemma image_mset_subseteq_mono: "A ⊆# B ==> image_mset f A ⊆# image_mset f B" by (metis image_mset_union subset_mset.le_iff_add)
lemma image_mset_subset_mono: "M ⊂# N ==> image_mset f M ⊂# image_mset f N" by (metis (no_types) Diff_eq_empty_iff_mset image_mset_Diff image_mset_is_empty_iff
image_mset_subseteq_mono subset_mset.less_le_not_le)
text‹
This allows to write not just filters like term‹{#x∈#M. x<c#}›
but also images like term‹{#x+x. x∈#M #}› and @{term [source]
"{#x+x|x∈#M. x<c#}"}, where the latter is currently displayed as term‹{#x+x|x∈#M. x<c#}›. ›
lemma in_image_mset: "y ∈# {#f x. x ∈# M#} ⟷ y ∈ f ` set_mset M" by simp
functor image_mset: image_mset proof - fix f g show"image_mset f ∘ image_mset g = image_mset (f ∘ g)" proof fix A show"(image_mset f ∘ image_mset g) A = image_mset (f ∘ g) A" by (induct A) simp_all qed show"image_mset id = id" proof fix A show"image_mset id A = id A" by (induct A) simp_all qed qed
lemma image_mset_id[simp]: "image_mset id x = x" unfolding id_def by auto
lemma image_mset_cong: "(∧x. x ∈# M ==> f x = g x) ==> {#f x. x ∈# M#} = {#g x. x ∈# M#}" by (induct M) auto
lemma image_mset_cong_pair: "(∀x y. (x, y) ∈# M ⟶ f x y = g x y) ==> {#f x y. (x, y) ∈# M#} = {#g x y. (x, y) ∈# M#}" by (metis image_mset_cong split_cong)
lemma image_mset_const_eq: "{#c. a ∈# M#} = replicate_mset (size M) c" by (induct M) simp_all
lemma image_mset_filter_mset_swap: "image_mset f (filter_mset (λx. P (f x)) M) = filter_mset P (image_mset f M)" by (induction M rule: multiset_induct) simp_all
lemma image_mset_eq_plusD: "image_mset f A = B + C ==>∃B' C'. A = B' + C' ∧ B = image_mset f B' ∧ C = image_mset f C'" proof (induction A arbitrary: B C) case empty thus ?caseby simp next case (add x A) show ?case proof (cases "f x ∈# B") case True with add.prems have"image_mset f A = (B - {#f x#}) + C" by (metis add_mset_remove_trivial image_mset_add_mset mset_subset_eq_single
subset_mset.add_diff_assoc2) thus ?thesis using add.IH add.prems by force next case False with add.prems have"image_mset f A = B + (C - {#f x#})" by (metis diff_single_eq_union diff_union_single_conv image_mset_add_mset union_iff
union_single_eq_member) thenshow ?thesis using add.IH add.prems by force qed qed
lemma image_mset_eq_image_mset_plusD: assumes"image_mset f A = image_mset f B + C"and inj_f: "inj_on f (set_mset A ∪ set_mset B)" shows"∃C'. A = B + C' ∧ C = image_mset f C'" using assms proof (induction A arbitrary: B C) case empty thus ?caseby simp next case (add x A) show ?case proof (cases "x ∈# B") case True with add.prems have"image_mset f A = image_mset f (B - {#x#}) + C" by (smt (verit) add_mset_add_mset_same_iff image_mset_add_mset insert_DiffM union_mset_add_mset_left) with add.IH have"∃M3'. A = B - {#x#} + M3' ∧ image_mset f M3' = C" by (smt (verit, del_insts) True Un_insert_left Un_insert_right add.prems(2) inj_on_insert
insert_DiffM set_mset_add_mset_insert) with True show ?thesis by auto next case False with add.prems(2) have"f x ∉# image_mset f B" by auto with add.prems(1) have"image_mset f A = image_mset f B + (C - {#f x#})" by (metis (no_types, lifting) diff_union_single_conv image_eqI image_mset_Diff
image_mset_single mset_subset_eq_single set_image_mset union_iff union_single_eq_diff
union_single_eq_member) with add.prems(2) add.IH have"∃M3'. A = B + M3' ∧ C - {#f x#} = image_mset f M3'" by auto thenshow ?thesis by (metis add.prems(1) add_diff_cancel_left' image_mset_Diff mset_subset_eq_add_left
union_mset_add_mset_right) qed qed
lemma image_mset_eq_plus_image_msetD: "image_mset f A = B + image_mset f C ==> inj_on f (set_mset A ∪ set_mset C) ==> ∃B'. A = B' + C ∧ B = image_mset f B'" unfolding add.commute[of B] add.commute[of _ C] by (rule image_mset_eq_image_mset_plusD; assumption)
subsection‹Further conversions›
primrec mset :: "'a list ==> 'a multiset"where "mset [] = {#}" | "mset (a # x) = add_mset a (mset x)"
lemma in_multiset_in_set: "x ∈# mset xs ⟷ x ∈ set xs" by (induct xs) simp_all
lemma count_mset: "count (mset xs) x = count_list xs x" by (induct xs) simp_all
lemma mset_zero_iff[simp]: "(mset x = {#}) = (x = [])" by (induct x) auto
lemma mset_zero_iff_right[simp]: "({#} = mset x) = (x = [])" by (induct x) auto
lemma mset_replicate [simp]: "mset (replicate n x) = replicate_mset n x" by (induction n) auto
lemma count_mset_gt_0: "x ∈ set xs ==> count (mset xs) x > 0" by (induction xs) auto
lemma count_mset_0_iff [simp]: "count (mset xs) x = 0 ⟷ x ∉ set xs" by (induction xs) auto
lemma mset_single_iff[iff]: "mset xs = {#x#} ⟷ xs = [x]" by (cases xs) auto
lemma mset_single_iff_right[iff]: "{#x#} = mset xs ⟷ xs = [x]" by (cases xs) auto
lemma set_mset_mset[simp]: "set_mset (mset xs) = set xs" by (induct xs) auto
lemma surj_mset: "surj mset" unfolding surj_def proof (rule allI) fix M show"∃xs. M = mset xs" by (induction M) (auto intro: exI[of _ "_ # _"]) qed
lemma distinct_count_atmost_1: "distinct x = (∀a. count (mset x) a = (if a ∈ set x then 1 else 0))" proof (induct x) case Nil thenshow ?caseby simp next case (Cons x xs) show ?case (is"?lhs ⟷ ?rhs") proof assume ?lhs thenshow ?rhs using Cons by simp next assume ?rhs thenhave"x ∉ set xs" by (simp split: if_splits) moreoverfrom‹?rhs›have"(∀a. count (mset xs) a = (if a ∈ set xs then 1 else 0))" by (auto split: if_splits simp add: count_eq_zero_iff) ultimatelyshow ?lhs using Cons by simp qed qed
lemma mset_eq_setD: assumes"mset xs = mset ys" shows"set xs = set ys" proof - from assms have"set_mset (mset xs) = set_mset (mset ys)" by simp thenshow ?thesis by simp qed
lemma set_eq_iff_mset_eq_distinct: ‹distinct x ==> distinct y ==> set x = set y ⟷ mset x = mset y› by (auto simp: multiset_eq_iff distinct_count_atmost_1)
lemma set_eq_iff_mset_remdups_eq: ‹set x = set y ⟷ mset (remdups x) = mset (remdups y)› using set_eq_iff_mset_eq_distinct by fastforce
lemma mset_eq_imp_distinct_iff: ‹distinct xs ⟷ distinct ys›if‹mset xs = mset ys› using that by (auto simp add: distinct_count_atmost_1 dest: mset_eq_setD)
lemma nth_mem_mset: "i < length ls ==> (ls ! i) ∈# mset ls" proof (induct ls arbitrary: i) case Nil thenshow ?caseby simp next case Cons thenshow ?caseby (cases i) auto qed
lemma mset_remove1[simp]: "mset (remove1 a xs) = mset xs - {#a#}" by (induct xs) (auto simp add: multiset_eq_iff)
lemma mset_eq_length: assumes"mset xs = mset ys" shows"length xs = length ys" using assms by (metis size_mset)
lemma mset_eq_length_filter: assumes"mset xs = mset ys" shows"count_list xs z = count_list ys z" using assms by (metis count_mset)
lemma fold_multiset_equiv: ‹List.fold f xs = List.fold f ys› if f: ‹∧x y. x ∈ set xs ==> y ∈ set xs ==> f x ∘ f y = f y ∘ f x› and‹mset xs = mset ys› using f ‹mset xs = mset ys› [symmetric] proof (induction xs arbitrary: ys) case Nil thenshow ?caseby simp next case (Cons x xs) thenhave *: ‹set ys = set (x # xs)› by (blast dest: mset_eq_setD) have‹∧x y. x ∈ set ys ==> y ∈ set ys ==> f x ∘ f y = f y ∘ f x› by (rule Cons.prems(1)) (simp_all add: *) moreoverfrom * have‹x ∈ set ys› by simp ultimatelyhave‹List.fold f ys = List.fold f (remove1 x ys) ∘ f x› by (fact fold_remove1_split) moreoverfrom Cons.prems have‹List.fold f xs = List.fold f (remove1 x ys)› by (auto intro: Cons.IH) ultimatelyshow ?case by simp qed
lemma fold_permuted_eq: ‹List.fold (⊙) xs z = List.fold (⊙) ys z› if‹mset xs = mset ys› and‹P z›and P: ‹∧x z. x ∈ set xs ==> P z ==> P (x ⊙ z)› and f: ‹∧x y z. x ∈ set xs ==> y ∈ set xs ==> P z ==> x ⊙ (y ⊙ z) = y ⊙ (x ⊙ z)› for f (infixl‹⊙›70) using‹P z› P f ‹mset xs = mset ys› [symmetric] proof (induction xs arbitrary: ys z) case Nil thenshow ?caseby simp next case (Cons x xs) thenhave *: ‹set ys = set (x # xs)› by (blast dest: mset_eq_setD) have‹P z› by (fact Cons.prems(1)) moreoverhave‹∧x z. x ∈ set ys ==> P z ==> P (x ⊙ z)› by (rule Cons.prems(2)) (simp_all add: *) moreoverhave‹∧x y z. x ∈ set ys ==> y ∈ set ys ==> P z ==> x ⊙ (y ⊙ z) = y ⊙ (x ⊙ z)› by (rule Cons.prems(3)) (simp_all add: *) moreoverfrom * have‹x ∈ set ys› by simp ultimatelyhave‹fold (⊙) ys z = fold (⊙) (remove1 x ys) (x ⊙ z)› by (induction ys arbitrary: z) auto moreoverfrom Cons.prems have‹fold (⊙) xs (x ⊙ z) = fold (⊙) (remove1 x ys) (x ⊙ z)› by (auto intro: Cons.IH) ultimatelyshow ?case by simp qed
lemma mset_insort [simp]: "mset (insort x xs) = add_mset x (mset xs)" by (induct xs) simp_all
lemma mset_map[simp]: "mset (map f xs) = image_mset f (mset xs)" by (induct xs) simp_all
lemma mset_removeAll_eq: ‹mset (removeAll x xs) = filter_mset ((≠) x) (mset xs)› by (induction xs) auto
lemma singleton_set_mset_subset: fixes X Y :: "'a list set" assumes"∀xs ∈ X. set xs ⊆ {a}""mset ` X ⊆ mset ` Y" shows"X ⊆ Y" proof fix xs assume"xs ∈ X" obtain ys where ys: "ys ∈ Y""mset xs = mset ys" using‹xs ∈ X› assms(2) by auto thenshow"xs ∈ Y"using‹xs ∈ X› assms(1) ys by (metis singleton_iff mset_eq_setD replicate_eqI set_empty subset_singletonD size_mset) qed
lemma singleton_set_mset_eq: fixes X Y :: "'a list set" assumes"∀xs ∈ X. set xs ⊆ {a}""mset ` X = mset ` Y" shows"X = Y" proof - have"∀ys ∈ Y. set ys ⊆ {a}" by (metis (mono_tags, lifting) assms image_iff mset_eq_setD) thus ?thesis by (metis antisym assms(1,2) singleton_set_mset_subset subset_refl) qed
global_interpretation mset_set: folding add_mset "{#}" defines mset_set = "folding_on.F add_mset {#}" by standard (simp add: fun_eq_iff)
lemma sum_multiset_singleton [simp]: "sum (λn. {#n#}) A = mset_set A" by (induction A rule: infinite_finite_induct) auto
lemma count_mset_set [simp]: "finite A ==> x ∈ A ==> count (mset_set A) x = 1" (is"PROP ?P") "¬ finite A ==> count (mset_set A) x = 0" (is"PROP ?Q") "x ∉ A ==> count (mset_set A) x = 0" (is"PROP ?R") proof - have *: "count (mset_set A) x = 0"if"x ∉ A"for A proof (cases "finite A") case False thenshow ?thesis by simp next case True from True ‹x ∉ A›show ?thesis by (induct A) auto qed thenshow"PROP ?P""PROP ?Q""PROP ?R" by (auto elim!: Set.set_insert) qed ― ‹TODO: maybe define const‹mset_set› also in terms of const‹Abs_multiset››
lemma elem_mset_set[simp, intro]: "finite A ==> x ∈# mset_set A ⟷ x ∈ A" by (induct A rule: finite_induct) simp_all
lemma mset_set_Union: "finite A ==> finite B ==> A ∩ B = {} ==> mset_set (A ∪ B) = mset_set A + mset_set B" by (induction A rule: finite_induct) auto
lemma filter_mset_mset_set [simp]: "finite A ==> filter_mset P (mset_set A) = mset_set {x∈A. P x}" proof (induction A rule: finite_induct) case (insert x A) from insert.hyps have"filter_mset P (mset_set (insert x A)) = filter_mset P (mset_set A) + mset_set (if P x then {x} else {})" by simp alsohave"filter_mset P (mset_set A) = mset_set {x∈A. P x}" by (rule insert.IH) alsofrom insert.hyps have"… + mset_set (if P x then {x} else {}) = mset_set ({x ∈ A. P x} ∪ (if P x then {x} else {}))" (is"_ = mset_set ?A") by (intro mset_set_Union [symmetric]) simp_all alsofrom insert.hyps have"?A = {y∈insert x A. P y}"by auto finallyshow ?case . qed simp_all
lemma mset_set_Diff: assumes"finite A""B ⊆ A" shows"mset_set (A - B) = mset_set A - mset_set B" proof - from assms have"mset_set ((A - B) ∪ B) = mset_set (A - B) + mset_set B" by (intro mset_set_Union) (auto dest: finite_subset) alsofrom assms have"A - B ∪ B = A"by blast finallyshow ?thesis by simp qed
lemma count_mset_set': "count (mset_set A) x = (if finite A ∧ x ∈ A then 1 else 0)" by auto
lemma subset_imp_msubset_mset_set: assumes"A ⊆ B""finite B" shows"mset_set A ⊆# mset_set B" proof (rule mset_subset_eqI) fix x :: 'a from assms have"finite A"by (rule finite_subset) with assms show"count (mset_set A) x ≤ count (mset_set B) x" by (cases "x ∈ A"; cases "x ∈ B") auto qed
lemma mset_set_set_mset_msubset: "mset_set (set_mset A) ⊆# A" proof (rule mset_subset_eqI) fix x show"count (mset_set (set_mset A)) x ≤ count A x" by (cases "x ∈# A") simp_all qed
lemma sorted_list_of_multiset_singleton [simp]: "sorted_list_of_multiset {#x#} = [x]" proof - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) show ?thesis by (simp add: sorted_list_of_multiset_def) qed
lemma sorted_list_of_multiset_insert [simp]: "sorted_list_of_multiset (add_mset x M) = List.insort x (sorted_list_of_multiset M)" proof - interpret comp_fun_commute insort by (fact comp_fun_commute_insort) show ?thesis by (simp add: sorted_list_of_multiset_def) qed
end
lemma mset_sorted_list_of_multiset[simp]: "mset (sorted_list_of_multiset M) = M" by (induct M) simp_all
lemma image_mset_map_of: "distinct (map fst xs) ==> {#the (map_of xs i). i ∈# mset (map fst xs)#} = mset (map snd xs)" proof (induction xs) case (Cons x xs) have"{#the (map_of (x # xs) i). i ∈# mset (map fst (x # xs))#} = add_mset (snd x) {#the (if i = fst x then Some (snd x) else map_of xs i). i ∈# mset (map fst xs)#}" (is"_ = add_mset _ ?A") by simp alsofrom Cons.prems have"?A = {#the (map_of xs i). i :# mset (map fst xs)#}" by (cases x, intro image_mset_cong) (auto simp: in_multiset_in_set) alsofrom Cons.prems have"… = mset (map snd xs)"by (intro Cons.IH) simp_all finallyshow ?caseby simp qed simp_all
lemma msubset_mset_set_iff[simp]: assumes"finite A""finite B" shows"mset_set A ⊆# mset_set B ⟷ A ⊆ B" using assms set_mset_mono subset_imp_msubset_mset_set by fastforce
lemma mset_set_eq_iff[simp]: assumes"finite A""finite B" shows"mset_set A = mset_set B ⟷ A = B" using assms by (fastforce dest: finite_set_mset_mset_set)
lemma image_mset_mset_set: ✐‹contributor ‹Lukas Bulwahn›› assumes"inj_on f A" shows"image_mset f (mset_set A) = mset_set (f ` A)" proof cases assume"finite A" from this ‹inj_on f A›show ?thesis by (induct A) auto next assume"infinite A" from this ‹inj_on f A›have"infinite (f ` A)" using finite_imageD by blast from‹infinite A›‹infinite (f ` A)›show ?thesis by simp qed
subsection‹More properties of the replicate, repeat, and image operations›
lemma in_replicate_mset[simp]: "x ∈# replicate_mset n y ⟷ n > 0 ∧ x = y" unfolding replicate_mset_def by (induct n) auto
lemma set_mset_replicate_mset_subset[simp]: "set_mset (replicate_mset n x) = (if n = 0 then {} else {x})" by auto
lemma size_replicate_mset[simp]: "size (replicate_mset n M) = n" by (induct n, simp_all)
lemma size_repeat_mset [simp]: "size (repeat_mset n A) = n * size A" by (induction n) auto
lemma size_multiset_sum [simp]: "size (∑x∈A. f x :: 'a multiset) = (∑x∈A. size (f x))" by (induction A rule: infinite_finite_induct) auto
lemma size_multiset_sum_list [simp]: "size (∑X←Xs. X :: 'a multiset) = (∑X←Xs. size X)" by (induction Xs) auto
lemma count_le_replicate_mset_subset_eq: "n ≤ count M x ⟷ replicate_mset n x ⊆# M" by (auto simp add: mset_subset_eqI) (metis count_replicate_mset subseteq_mset_def)
lemma replicate_count_mset_eq_filter_eq: "replicate (count (mset xs) k) k = filter (HOL.eq k) xs" by (induct xs) auto
lemma replicate_mset_eq_empty_iff [simp]: "replicate_mset n a = {#} ⟷ n = 0" by (induct n) simp_all
lemma replicate_mset_eq_iff: "replicate_mset m a = replicate_mset n b ⟷ m = 0 ∧ n = 0 ∨ m = n ∧ a = b" by (auto simp add: multiset_eq_iff)
lemma repeat_mset_cancel1: "repeat_mset a A = repeat_mset a B ⟷ A = B ∨ a = 0" by (auto simp: multiset_eq_iff)
lemma repeat_mset_cancel2: "repeat_mset a A = repeat_mset b A ⟷ a = b ∨ A = {#}" by (auto simp: multiset_eq_iff)
lemma repeat_mset_eq_empty_iff: "repeat_mset n A = {#} ⟷ n = 0 ∨ A = {#}" by (cases n) auto
lemma image_replicate_mset [simp]: "image_mset f (replicate_mset n a) = replicate_mset n (f a)" by (induct n) simp_all
lemma replicate_mset_msubseteq_iff: "replicate_mset m a ⊆# replicate_mset n b ⟷ m = 0 ∨ a = b ∧ m ≤ n" by (cases m)
(auto simp: insert_subset_eq_iff simp flip: count_le_replicate_mset_subset_eq)
lemma msubseteq_replicate_msetE: assumes"A ⊆# replicate_mset n a" obtains m where"m ≤ n"and"A = replicate_mset m a" proof (cases "n = 0") case True with assms that show thesis by simp next case False from assms have"set_mset A ⊆ set_mset (replicate_mset n a)" by (rule set_mset_mono) with False have"set_mset A ⊆ {a}" by simp thenhave"∃m. A = replicate_mset m a" proof (induction A) case empty thenshow ?case by simp next case (add b A) thenobtain m where"A = replicate_mset m a" by auto with add.prems show ?case by (auto intro: exI [of _ "Suc m"]) qed thenobtain m where A: "A = replicate_mset m a" .. with assms have"m ≤ n" by (auto simp add: replicate_mset_msubseteq_iff) thenshow thesis using A .. qed
lemma count_image_mset_lt_imp_lt_raw: assumes "finite A"and "A = set_mset M ∪ set_mset N"and "count (image_mset f M) b < count (image_mset f N) b" shows"∃x. f x = b ∧ count M x < count N x" using assms proof (induct A arbitrary: M N b rule: finite_induct) case (insert x F) note fin = this(1) and x_ni_f = this(2) and ih = this(3) and x_f_eq_m_n = this(4) and
cnt_b = this(5)
let ?Ma = "{#y ∈# M. y ≠ x#}" let ?Mb = "{#y ∈# M. y = x#}" let ?Na = "{#y ∈# N. y ≠ x#}" let ?Nb = "{#y ∈# N. y = x#}"
have m_part: "M = ?Mb + ?Ma"and n_part: "N = ?Nb + ?Na" using multiset_partition by blast+
have f_eq_ma_na: "F = set_mset ?Ma ∪ set_mset ?Na" using x_f_eq_m_n x_ni_f by auto
show ?case proof (cases "count (image_mset f ?Ma) b < count (image_mset f ?Na) b") case cnt_ba: True obtain xa where"f xa = b"and"count ?Ma xa < count ?Na xa" using ih[OF f_eq_ma_na cnt_ba] by blast thus ?thesis by (metis count_filter_mset not_less0) next case cnt_ba: False have fx_eq_b: "f x = b" using cnt_b cnt_ba by (subst (asm) m_part, subst (asm) n_part,
auto simp: filter_eq_replicate_mset split: if_splits) moreoverhave"count M x < count N x" using cnt_b cnt_ba by (subst (asm) m_part, subst (asm) n_part,
auto simp: filter_eq_replicate_mset split: if_splits) ultimatelyshow ?thesis by blast qed qed auto
lemma count_image_mset_lt_imp_lt: assumes cnt_b: "count (image_mset f M) b < count (image_mset f N) b" shows"∃x. f x = b ∧ count M x < count N x" by (rule count_image_mset_lt_imp_lt_raw[of "set_mset M ∪ set_mset N", OF _ refl cnt_b]) auto
lemma count_image_mset_le_imp_lt_raw: assumes "finite A"and "A = set_mset M ∪ set_mset N"and "count (image_mset f M) (f a) + count N a < count (image_mset f N) (f a) + count M a" shows"∃b. f b = f a ∧ count M b < count N b" using assms proof (induct A arbitrary: M N rule: finite_induct) case (insert x F) note fin = this(1) and x_ni_f = this(2) and ih = this(3) and x_f_eq_m_n = this(4) and
cnt_lt = this(5)
let ?Ma = "{#y ∈# M. y ≠ x#}" let ?Mb = "{#y ∈# M. y = x#}" let ?Na = "{#y ∈# N. y ≠ x#}"
let ?Nb = "{#y \<in># N. y = x#}"
have m_part: "M = ?Mb + ?Ma"and n_part: "N = ?Nb + ?Na" using multiset_partition by blast+
have f_eq_ma_na: "F = set_mset ?Ma \<union> set_mset ?Na" using x_f_eq_m_n x_ni_f by auto
show ?case
proof (cases "f x = f a") case fx_ne_fa: False
have cnt_fma_fa: "count (image_mset f ?Ma) (f a) = count (image_mset f M) (f a)" using fx_ne_fa by (subst (2) m_part) (auto simp: filter_eq_replicate_mset)
have cnt_fna_fa: "count (image_mset f ?Na) (f a) = count (image_mset f N) (f a)" using fx_ne_fa by (subst (2) n_part) (auto simp: filter_eq_replicate_mset)
have cnt_ma_a: "count ?Ma a = count M a" using fx_ne_fa by (subst (2) m_part) (auto simp: filter_eq_replicate_mset)
have cnt_na_a: "count ?Na a = count N a" using fx_ne_fa by (subst (2) n_part) (auto simp: filter_eq_replicate_mset)
obtain b where fb_eq_fa: "f b = f a"and cnt_b: "count ?Ma b < count ?Na b" using ih[OF f_eq_ma_na] cnt_lt unfolding cnt_fma_fa cnt_fna_fa cnt_ma_a cnt_na_a by blast
have fx_ne_fb: "f x \<noteq> f b" using fb_eq_fa fx_ne_fa by simp
have cnt_ma_b: "count ?Ma b = count M b" using fx_ne_fb by (subst (2) m_part) auto
have cnt_na_b: "count ?Na b = count N b" using fx_ne_fb by (subst (2) n_part) auto
show ?thesis using fb_eq_fa cnt_b unfolding cnt_ma_b cnt_na_b by blast
next case fx_eq_fa: True
show ?thesis
proof (cases "x = a") case x_eq_a: True
have "count (image_mset f ?Ma) (f a) + count ?Na a
< count (image_mset f ?Na) (f a) + count ?Ma a" using cnt_lt x_eq_a by (subst (asm) (12) m_part, subst (asm) (12) n_part, auto simp: filter_eq_replicate_mset)
thus ?thesis using ih[OF f_eq_ma_na] by (metis count_filter_mset nat_neq_iff)
next case x_ne_a: False
show ?thesis
proof (cases "count M x < count N x") caseTrue
thus ?thesis using fx_eq_fa by blast
next caseFalse
hence cnt_x: "count M x \<ge> count N x"
by fastforce
have "count M x + count (image_mset f ?Ma) (f a) + count ?Na a
< count N x + count (image_mset f ?Na) (f a) + count ?Ma a" using cnt_lt x_ne_a fx_eq_fa by (subst (asm) (12) m_part, subst (asm) (12) n_part, auto simp: filter_eq_replicate_mset)
hence "count (image_mset f ?Ma) (f a) + count ?Na a
< count (image_mset f ?Na) (f a) + count ?Ma a" using cnt_x by linarith
thus ?thesis using ih[OF f_eq_ma_na] by (metis count_filter_mset nat_neq_iff)
qed
qed
qed
qed auto
lemma count_image_mset_le_imp_lt:
assumes "count (image_mset f M) (f a) \<le> count (image_mset f N) (f a)"and "count M a > count N a"
shows "\<exists>b. f b = f a \<and> count M b < count N b" using assms by (auto intro: count_image_mset_le_imp_lt_raw[of "set_mset M \<union> set_mset N"])
lemma size_filter_unsat_elem:
assumes "x \<in># M"and"\<not> P x"
shows "size {#x \<in># M. P x#} < size M"
proof -
have "size (filter_mset P M) \<noteq> size M" using assms
by (metis dual_order.strict_iff_order filter_mset_eq_conv mset_subset_size subset_mset.nless_le)
then show ?thesis
by (meson leD nat_neq_iff size_filter_mset_lesseq)
qed
lemma size_filter_ne_elem: "x \<in># M \<Longrightarrow> size {#y \<in># M. y \<noteq> x#} < size M"
by (simp add: size_filter_unsat_elem[of x M "\<lambda>y. y \<noteq> x"])
lemma size_eq_ex_count_lt:
assumes "size M = size N"and"M \<noteq> N"
shows "\<exists>x. count M x < count N x"
proof -
from \<open>M \<noteq> N\<close> obtain x where "count M x \<noteq> count N x" using count_inject by blast
then consider (lt) "count M x < count N x" | (gt) "count M x > count N x"
by linarith
then show ?thesis
proof cases case lt
then show ?thesis ..
next case gt
from \<open>size M = size N\<close> have "size {#y \<in># M. y = x#} + size {#y \<in># M. y \<noteq> x#} =
size {#y \<in># N. y = x#} + size {#y \<in># N. y \<noteq> x#}" using multiset_partition by (metis size_union)
with gt have *: "size {#y \<in># M. y \<noteq> x#} < size {#y \<in># N. y \<noteq> x#}"
by (simp add: filter_eq_replicate_mset)
then obtain y where "count {#y \<in># M. y \<noteq> x#} y < count {#y \<in># N. y \<noteq> x#} y" using size_lt_imp_ex_count_lt[OF *] by blast
then have "count M y < count N y"
by (metis count_filter_mset less_asym)
then show ?thesis ..
qed
qed
subsection \<open>Big operators\<close>
locale comm_monoid_mset = comm_monoid
begin
interpretation comp_fun_commute f
by standard (simp add: fun_eq_iff left_commute)
interpretation comp?: comp_fun_commute "f \<circ> g"
by (fact comp_comp_fun_commute)
context
begin
definition F :: "'a multiset \<Rightarrow> 'a"
where eq_fold: "F M = fold_mset f \<^bold>1 M"
lemma singleton [simp]: "F {#x#} = x"
proof -
interpret comp_fun_commute
by standard (simp add: fun_eq_iff left_commute)
show ?thesis by (simp add: eq_fold)
qed
lemma union [simp]: "F (M + N) = F M \<^bold>* F N"
proof -
interpret comp_fun_commute f
by standard (simp add: fun_eq_iff left_commute)
show ?thesis
by (induct N) (simp_all add: left_commute eq_fold)
qed
lemma add_mset [simp]: "F (add_mset x N) = x \<^bold>* F N"
unfolding add_mset_add_single[of x N] union by (simp add: ac_simps)
lemma insert [simp]:
shows "F (image_mset g (add_mset x A)) = g x \<^bold>* F (image_mset g A)"
by (simp add: eq_fold)
lemma remove:
assumes "x \<in># A"
shows "F A = x \<^bold>* F (A - {#x#})" using multi_member_split[OF assms] by auto
lemma neutral: "\<forall>x\<in>#A. x = \<^bold>1 \<Longrightarrow> F A = \<^bold>1"
by (induct A) simp_all
lemma neutral_const [simp]: "F (image_mset (\<lambda>_. \<^bold>1) A) = \<^bold>1"
by (simp add: neutral)
private lemma F_image_mset_product: "F {#g x j \<^bold>* F {#g i j. i \<in># A#}. j \<in># B#} =
F (image_mset (g x) B) \<^bold>* F {#F {#g i j. i \<in># A#}. j \<in># B#}"
by (induction B) (simp_all add: left_commute semigroup.assoc semigroup_axioms)
lemma swap: "F (image_mset (\<lambda>i. F (image_mset (g i) B)) A) =
F (image_mset (\<lambda>j. F (image_mset (\<lambda>i. g i j) A)) B)"
apply (induction A, simp)
apply (induction B, auto simp add: F_image_mset_product ac_simps)
done
lemma distrib: "F (image_mset (\<lambda>x. g x \<^bold>* h x) A) = F (image_mset g A) \<^bold>* F (image_mset h A)"
by (induction A) (auto simp: ac_simps)
lemma union_disjoint: "A \<inter># B = {#} \<Longrightarrow> F (image_mset g (A \<union># B)) = F (image_mset g A) \<^bold>* F (image_mset g B)"
by (induction A) (auto simp: ac_simps)
end
end
lemma comp_fun_commute_plus_mset[simp]: "comp_fun_commute ((+) :: 'a multiset \<Rightarrow> _ \<Rightarrow> _)"
by standard (simp add: add_ac comp_def)
lemma in_mset_fold_plus_iff[iff]: "x \<in># fold_mset (+) M NN \<longleftrightarrow> x \<in># M \<or> (\<exists>N. N \<in># NN \<and> x \<in># N)"
by (induct NN) auto
context comm_monoid_add
begin
sublocale sum_mset: comm_monoid_mset plus 0
defines sum_mset = sum_mset.F ..
lemma sum_unfold_sum_mset: "sum f A = sum_mset (image_mset f (mset_set A))"
by (cases "finite A") (induct A rule: finite_induct, simp_all)
end
notation sum_mset (\<open>\<Sum>\<^sub>#\<close>)
syntax (ASCII) "_sum_mset_image" :: "pttrn \<Rightarrow> 'b set \<Rightarrow> 'a \<Rightarrow> 'a::comm_monoid_add"
(\<open>(\<open>indent=3 notation=\<open>binder SUM\<close>\<close>SUM _:#_. _)\<close> [0, 51, 10] 10)
syntax "_sum_mset_image" :: "pttrn \<Rightarrow> 'b set \<Rightarrow> 'a \<Rightarrow> 'a::comm_monoid_add"
(\<open>(\<open>indent=3 notation=\<open>binder \<Sum>\<close>\<close>\<Sum>_\<in>#_. _)\<close> [0, 51, 10] 10)
syntax_consts "_sum_mset_image" \<rightleftharpoons> sum_mset
translations "\<Sum>i \<in># A. b" \<rightleftharpoons> "CONST sum_mset (CONST image_mset (\<lambda>i. b) A)"
context comm_monoid_add
begin
lemma sum_mset_sum_list: "sum_mset (mset xs) = sum_list xs"
by (induction xs) auto
end
context canonically_ordered_monoid_add
begin
lemma sum_mset_0_iff [simp]: "sum_mset M = 0 \<longleftrightarrow> (\<forall>x \<in> set_mset M. x = 0)"
by (induction M) auto
end
context ordered_comm_monoid_add
begin
lemma sum_mset_mono: "sum_mset (image_mset f K) \<le> sum_mset (image_mset g K)" if"\<And>i. i \<in># K \<Longrightarrow> f i \<le> g i" using that by (induction K) (simp_all add: add_mono)
end
context cancel_comm_monoid_add
begin
lemma sum_mset_diff: "sum_mset (M - N) = sum_mset M - sum_mset N"if"N \<subseteq># M"for M N :: "'a multiset" using that by (auto simp add: subset_mset.le_iff_add)
end
context semiring_0
begin
lemma sum_mset_distrib_left: "c * (\<Sum>x \<in># M. f x) = (\<Sum>x \<in># M. c * f(x))"
by (induction M) (simp_all add: algebra_simps)
lemma sum_mset_distrib_right: "(\<Sum>x \<in># M. f x) * c = (\<Sum>x \<in># M. f x * c)"
by (induction M) (simp_all add: algebra_simps)
end
lemma sum_mset_product:
fixes f :: "'a::{comm_monoid_add,times} \<Rightarrow> 'b::semiring_0"
shows "(\<Sum>i \<in># A. f i) * (\<Sum>i \<in># B. g i) = (\<Sum>i\<in>#A. \<Sum>j\<in>#B. f i * g j)"
by (subst sum_mset.swap) (simp add: sum_mset_distrib_left sum_mset_distrib_right)
context semiring_1
begin
lemma sum_mset_replicate_mset [simp]: "sum_mset (replicate_mset n a) = of_nat n * a"
by (induction n) (simp_all add: algebra_simps)
lemma sum_mset_delta: "sum_mset (image_mset (\<lambda>x. if x = y then c else 0) A) = c * of_nat (count A y)"
by (induction A) (simp_all add: algebra_simps)
lemma sum_mset_delta': "sum_mset (image_mset (\<lambda>x. if y = x then c else 0) A) = c * of_nat (count A y)"
by (induction A) (simp_all add: algebra_simps)
end
lemma of_nat_sum_mset [simp]: "of_nat (sum_mset A) = sum_mset (image_mset of_nat A)"
by (induction A) auto
lemma size_eq_sum_mset: "size M = (\<Sum>a\<in>#M. 1)" using image_mset_const_eq [of "1::nat" M] by simp
lemma size_mset_set [simp]: "size (mset_set A) = card A"
by (simp only: size_eq_sum_mset card_eq_sum sum_unfold_sum_mset)
lemma sum_mset_constant [simp]:
fixes y :: "'b::semiring_1"
shows \<open>(\<Sum>x\<in>#A. y) = of_nat (size A) * y\<close>
by (induction A) (auto simp: algebra_simps)
lemma set_mset_Union_mset[simp]: "set_mset (\<Sum>\<^sub># MM) = (\<Union>M \<in> set_mset MM. set_mset M)"
by (induct MM) auto
lemma in_Union_mset_iff[iff]: "x \<in># \<Sum>\<^sub># MM \<longleftrightarrow> (\<exists>M. M \<in># MM \<and> x \<in># M)"
by (induct MM) auto
lemma count_sum: "count (sum f A) x = sum (\<lambda>a. count (f a) x) A"
by (induct A rule: infinite_finite_induct) simp_all
lemma sum_eq_empty_iff:
assumes "finite A"
shows "sum f A = {#} \<longleftrightarrow> (\<forall>a\<in>A. f a = {#})" using assms by induct simp_all
lemma mset_concat: "mset (concat xss) = (\<Sum>xs\<leftarrow>xss. mset xs)"
by (induction xss) auto
lemma set_mset_sum_list [simp]: "set_mset (sum_list xs) = (\<Union>x\<in>set xs. set_mset x)"
by (induction xs) auto
lemma filter_mset_sum_list: "filter_mset P (sum_list xs) = sum_list (map (filter_mset P) xs)"
by (induction xs) simp_all
lemma sum_mset_singleton_mset [simp]: "(\<Sum>x\<in>#A. {#f x#}) = image_mset f A"
by (induction A) auto
lemma sum_list_singleton_mset [simp]: "(\<Sum>x\<leftarrow>xs. {#f x#}) = image_mset f (mset xs)"
by (induction xs) auto
lemma Union_mset_empty_conv[simp]: "\<Sum>\<^sub># M = {#} \<longleftrightarrow> (\<forall>i\<in>#M. i = {#})"
by (induction M) auto
lemma Union_image_single_mset[simp]: "\<Sum>\<^sub># (image_mset (\<lambda>x. {#x#}) m) = m"
by(induction m) auto
lemma size_mset_sum_mset_conv [simp]: "size (\<Sum>\<^sub># A :: 'a multiset) = (\<Sum>X\<in>#A. size X)"
by (induction A) auto
lemma sum_mset_image_mset_mono_strong:
assumes "A \<subseteq># B"and f_subeq_g: "\<And>x. x \<in># A \<Longrightarrow> f x \<subseteq># g x"
shows "(\<Sum>x\<in>#A. f x) \<subseteq># (\<Sum>x\<in>#B. g x)"
proof -
define B' where "B' = B - A"
have "B = A + B'" using B'_def assms(1) by fastforce
have "\<Sum>\<^sub># (image_mset f A) \<subseteq># \<Sum>\<^sub># (image_mset g A)" using f_subeq_g by (induction A) (auto intro!: subset_mset.add_mono)
also have "\<dots> \<subseteq># \<Sum>\<^sub># (image_mset g A) + \<Sum>\<^sub># (image_mset g B')"
by simp
also have "\<dots> = \<Sum>\<^sub># (image_mset g A + image_mset g B')"
by simp
also have "\<dots> = \<Sum>\<^sub># (image_mset g (A + B'))"
by simp
also have "\<dots> = \<Sum>\<^sub># (image_mset g B)"
unfolding \<open>B = A + B'\<close> ..
finally show ?thesis .
qed
context comm_monoid_mult
begin
sublocale prod_mset: comm_monoid_mset times 1
defines prod_mset = prod_mset.F ..
lemma prod_mset_empty: "prod_mset {#} = 1"
by (fact prod_mset.empty)
lemma prod_mset_singleton: "prod_mset {#x#} = x"
by (fact prod_mset.singleton)
lemma prod_mset_Un: "prod_mset (A + B) = prod_mset A * prod_mset B"
by (fact prod_mset.union)
lemma prod_mset_prod_list: "prod_mset (mset xs) = prod_list xs"
by (induct xs) auto
lemma prod_mset_replicate_mset [simp]: "prod_mset (replicate_mset n a) = a ^ n"
by (induct n) simp_all
lemma prod_unfold_prod_mset: "prod f A = prod_mset (image_mset f (mset_set A))"
by (cases "finite A") (induct A rule: finite_induct, simp_all)
lemma prod_mset_multiplicity: "prod_mset M = prod (\<lambda>x. x ^ count M x) (set_mset M)"
by (simp add: fold_mset_def prod.eq_fold prod_mset.eq_fold funpow_times_power comp_def)
lemma prod_mset_delta: "prod_mset (image_mset (\<lambda>x. if x = y then c else 1) A) = c ^ count A y"
by (induction A) simp_all
lemma prod_mset_delta': "prod_mset (image_mset (\<lambda>x. if y = x then c else 1) A) = c ^ count A y"
by (induction A) simp_all
lemma prod_mset_subset_imp_dvd:
assumes "A \<subseteq># B"
shows "prod_mset A dvd prod_mset B"
proof -
from assms have "B = (B - A) + A" by (simp add: subset_mset.diff_add)
also have "prod_mset \<dots> = prod_mset (B - A) * prod_mset A" by simp
also have "prod_mset A dvd \<dots>" by simp
finally show ?thesis .
qed
lemma dvd_prod_mset:
assumes "x \<in># A"
shows "x dvd prod_mset A" using assms prod_mset_subset_imp_dvd [of "{#x#}" A] by simp
syntax (ASCII) "_prod_mset_image" :: "pttrn \<Rightarrow> 'b set \<Rightarrow> 'a \<Rightarrow> 'a::comm_monoid_mult"
(\<open>(\<open>indent=3 notation=\<open>binder PROD\<close>\<close>PROD _:#_. _)\<close> [0, 51, 10] 10)
syntax "_prod_mset_image" :: "pttrn \<Rightarrow> 'b set \<Rightarrow> 'a \<Rightarrow> 'a::comm_monoid_mult"
(\<open>(\<open>indent=3 notation=\<open>binder \<Prod>\<close>\<close>\<Prod>_\<in>#_. _)\<close> [0, 51, 10] 10)
syntax_consts "_prod_mset_image" \<rightleftharpoons> prod_mset
translations "\<Prod>i \<in># A. b" \<rightleftharpoons> "CONST prod_mset (CONST image_mset (\<lambda>i. b) A)"
lemma prod_mset_constant [simp]: "(\<Prod>_\<in>#A. c) = c ^ size A"
by (simp add: image_mset_const_eq)
lemma (in semidom) prod_mset_zero_iff [iff]: "prod_mset A = 0 \<longleftrightarrow> 0 \<in># A"
by (induct A) auto
lemma (in semidom_divide) prod_mset_diff:
assumes "B \<subseteq># A"and"0 \<notin># B"
shows "prod_mset (A - B) = prod_mset A div prod_mset B"
proof -
from assms obtain C where "A = B + C"
by (metis subset_mset.add_diff_inverse)
with assms show ?thesis by simp
qed
lemma (in semidom_divide) prod_mset_minus:
assumes "a \<in># A"and"a \<noteq> 0"
shows "prod_mset (A - {#a#}) = prod_mset A div a" using assms prod_mset_diff [of "{#a#}" A] by auto
lemma (in normalization_semidom) normalize_prod_mset_normalize: "normalize (prod_mset (image_mset normalize A)) = normalize (prod_mset A)"
proof (induction A) case (add x A)
have "normalize (prod_mset (image_mset normalize (add_mset x A))) =
normalize (x * normalize (prod_mset (image_mset normalize A)))"
by simp
also note add.IH
finally show ?case by simp
qed auto
lemma (in algebraic_semidom) is_unit_prod_mset_iff: "is_unit (prod_mset A) \<longleftrightarrow> (\<forall>x \<in># A. is_unit x)"
by (induct A) (auto simp: is_unit_mult_iff)
lemma (in normalization_semidom_multiplicative) normalize_prod_mset: "normalize (prod_mset A) = prod_mset (image_mset normalize A)"
by (induct A) (simp_all add: normalize_mult)
lemma (in normalization_semidom_multiplicative) normalized_prod_msetI:
assumes "\<And>a. a \<in># A \<Longrightarrow> normalize a = a"
shows "normalize (prod_mset A) = prod_mset A"
proof -
from assms have "image_mset normalize A = A"
by (induct A) simp_all
then show ?thesis by (simp add: normalize_prod_mset)
qed
lemma image_prod_mset_multiplicity: "prod_mset (image_mset f M) = prod (\<lambda>x. f x ^ count M x) (set_mset M)"
proof (induction M) case (add x M)
show ?case
proof (cases "x \<in> set_mset M") caseTrue
have "(\<Prod>y\<in>set_mset (add_mset x M). f y ^ count (add_mset x M) y) =
(\<Prod>y\<in>set_mset M. (if y = x then f x else1) * f y ^ count M y)" usingTrue add by (intro prod.cong) auto
also have "\<dots> = f x * (\<Prod>y\<in>set_mset M. f y ^ count M y)" usingTrue by (subst prod.distrib) auto
also note add.IH [symmetric]
finally show ?thesis usingTrue by simp
next caseFalse
hence "(\<Prod>y\<in>set_mset (add_mset x M). f y ^ count (add_mset x M) y) =
f x * (\<Prod>y\<in>set_mset M. f y ^ count (add_mset x M) y)"
by (auto simp: not_in_iff)
also have "(\<Prod>y\<in>set_mset M. f y ^ count (add_mset x M) y) =
(\<Prod>y\<in>set_mset M. f y ^ count M y)" usingFalse by (intro prod.cong) auto
also note add.IH [symmetric]
finally show ?thesis by simp
qed
qed auto
subsection \<open>Multiset as order-ignorant lists\<close>
context linorder
begin
lemma mset_insort [simp]: "mset (insort_key k x xs) = add_mset x (mset xs)"
by (induct xs) simp_all
lemma mset_sort [simp]: "mset (sort_key k xs) = mset xs"
by (induct xs) simp_all
text \<open> This lemma shows which properties suffice to show that a function
\<open>f\<close> with \<open>f xs = ys\<close> behaves like sort.
\<close>
lemma properties_for_sort_key:
assumes "mset ys = mset xs" and"\<And>k. k \<in> set ys \<Longrightarrow> filter (\<lambda>x. f k = f x) ys = filter (\<lambda>x. f k = f x) xs" and"sorted (map f ys)"
shows "sort_key f xs = ys" using assms
proof (induct xs arbitrary: ys) case Nil then show ?case by simp
next case (Cons x xs)
from Cons.prems(2) have "\<forall>k \<in> set ys. filter (\<lambda>x. f k = f x) (remove1 x ys) = filter (\<lambda>x. f k = f x) xs"
by (simp add: filter_remove1)
with Cons.prems have "sort_key f xs = remove1 x ys"
by (auto intro!: Cons.hyps simp add: sorted_map_remove1)
moreover from Cons.prems have "x \<in># mset ys"
by auto
then have "x \<in> set ys"
by simp
ultimately show ?caseusing Cons.prems by (simp add: insort_key_remove1)
qed
lemma properties_for_sort:
assumes multiset: "mset ys = mset xs" and"sorted ys"
shows "sort xs = ys"
proof (rule properties_for_sort_key)
from multiset show "mset ys = mset xs" .
from \<open>sorted ys\<close> show "sorted (map (\<lambda>x. x) ys)" by simp
from multiset have "length (filter (\<lambda>y. k = y) ys) = length (filter (\<lambda>x. k = x) xs)"for k
by (metis mset_filter size_mset)
then have "replicate (length (filter (\<lambda>y. k = y) ys)) k =
replicate (length (filter (\<lambda>x. k = x) xs)) k" for k
by simp
then show "k \<in> set ys \<Longrightarrow> filter (\<lambda>y. k = y) ys = filter (\<lambda>x. k = x) xs"for k
by (simp add: replicate_length_filter)
qed
lemma sort_key_inj_key_eq:
assumes mset_equal: "mset xs = mset ys" and"inj_on f (set xs)" and"sorted (map f ys)"
shows "sort_key f xs = ys"
proof (rule properties_for_sort_key)
from mset_equal
show "mset ys = mset xs" by simp
from \<open>sorted (map f ys)\<close>
show "sorted (map f ys)" .
show "[x\<leftarrow>ys . f k = f x] = [x\<leftarrow>xs . f k = f x]"if"k \<in> set ys"for k
proof -
from mset_equal
have set_equal: "set xs = set ys" by (rule mset_eq_setD)
with that have "insert k (set ys) = set ys" by auto
with \<open>inj_on f (set xs)\<close> have inj: "inj_on f (insert k (set ys))"
by (simp add: set_equal)
from inj have "[x\<leftarrow>ys . f k = f x] = filter (HOL.eq k) ys"
by (auto intro!: inj_on_filter_key_eq)
also have "\<dots> = replicate (count (mset ys) k) k"
by (simp add: replicate_count_mset_eq_filter_eq)
also have "\<dots> = replicate (count (mset xs) k) k" using mset_equal by simp
also have "\<dots> = filter (HOL.eq k) xs"
by (simp add: replicate_count_mset_eq_filter_eq)
also have "\<dots> = [x\<leftarrow>xs . f k = f x]" using inj by (auto intro!: inj_on_filter_key_eq [symmetric] simp add: set_equal)
finally show ?thesis .
qed
qed
lemma sort_key_eq_sort_key:
assumes "mset xs = mset ys" and"inj_on f (set xs)"
shows "sort_key f xs = sort_key f ys"
by (rule sort_key_inj_key_eq) (simp_all add: assms)
lemma sort_key_by_quicksort: "sort_key f xs = sort_key f [x\<leftarrow>xs. f x < f (xs ! (length xs div 2))]
@ [x\<leftarrow>xs. f x = f (xs ! (length xs div 2))]
@ sort_key f [x\<leftarrow>xs. f x > f (xs ! (length xs div 2))]" (is "sort_key f ?lhs = ?rhs")
proof (rule properties_for_sort_key)
show "mset ?rhs = mset ?lhs"
by (rule multiset_eqI) auto
show "sorted (map f ?rhs)"
by (auto simp add: sorted_append intro: sorted_map_same)
next
fix l
assume "l \<in> set ?rhs"
let ?pivot = "f (xs ! (length xs div 2))"
have *: "\<And>x. f l = f x \<longleftrightarrow> f x = f l" by auto
have "[x \<leftarrow> sort_key f xs . f x = f l] = [x \<leftarrow> xs. f x = f l]"
unfolding filter_sort by (rule properties_for_sort_key) (auto intro: sorted_map_same)
with * have **: "[x \<leftarrow> sort_key f xs . f l = f x] = [x \<leftarrow> xs. f l = f x]" by simp
have "\<And>x P. P (f x) ?pivot \<and> f l = f x \<longleftrightarrow> P (f l) ?pivot \<and> f l = f x" by auto
then have "\<And>P. [x \<leftarrow> sort_key f xs . P (f x) ?pivot \<and> f l = f x] =
[x \<leftarrow> sort_key f xs. P (f l) ?pivot \<and> f l = f x]" by simp
note *** = this [of "(<)"] this [of "(>)"] this [of "(=)"]
show "[x \<leftarrow> ?rhs. f l = f x] = [x \<leftarrow> ?lhs. f l = f x]"
proof (cases "f l" ?pivot rule: linorder_cases) case less
then have "f l \<noteq> ?pivot"and"\<not> f l > ?pivot" by auto
with less show ?thesis
by (simp add: filter_sort [symmetric] ** ***)
next case equal then show ?thesis
by (simp add: * less_le)
next case greater
then have "f l \<noteq> ?pivot"and"\<not> f l < ?pivot" by auto
with greater show ?thesis
by (simp add: filter_sort [symmetric] ** ***)
qed
qed
lemma sort_by_quicksort: "sort xs = sort [x\<leftarrow>xs. x < xs ! (length xs div 2)]
@ [x\<leftarrow>xs. x = xs ! (length xs div 2)]
@ sort [x\<leftarrow>xs. x > xs ! (length xs div 2)]" (is "sort ?lhs = ?rhs") using sort_key_by_quicksort [of "\<lambda>x. x", symmetric] by simp
lemma sort_append:
assumes "\<And>x y. x \<in> set xs \<Longrightarrow> y \<in> set ys \<Longrightarrow> x \<le> y"
shows "sort (xs @ ys) = sort xs @ sort ys" using assms by (intro properties_for_sort) (auto simp: sorted_append)
lemma sort_append_replicate_left: "(\<And>y. y \<in> set xs \<Longrightarrow> x \<le> y) \<Longrightarrow> sort (replicate n x @ xs) = replicate n x @ sort xs"
by (subst sort_append) auto
lemma sort_append_replicate_right: "(\<And>y. y \<in> set xs \<Longrightarrow> x \<ge> y) \<Longrightarrow> sort (xs @ replicate n x) = sort xs @ replicate n x"
by (subst sort_append) auto
text \<open>A stable parameterized quicksort\<close>
definition part :: "('b \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> 'b list \<Rightarrow> 'b list \<times> 'b list \<times> 'b list" where "part f pivot xs = ([x \<leftarrow> xs. f x < pivot], [x \<leftarrow> xs. f x = pivot], [x \<leftarrow> xs. pivot < f x])"
lemma part_code [code]: "part f pivot [] = ([], [], [])" "part f pivot (x # xs) = (let (lts, eqs, gts) = part f pivot xs; x' = f x in if x' < pivot then (x # lts, eqs, gts) elseif x' > pivot then (lts, eqs, x # gts) else (lts, x # eqs, gts))"
by (auto simp add: part_def Let_def split_def)
lemma sort_key_by_quicksort_code [code]: "sort_key f xs =
(case xs of
[] \<Rightarrow> []
| [x] \<Rightarrow> xs
| [x, y] \<Rightarrow> (if f x \<le> f y then xs else [y, x])
| _ \<Rightarrow>
let (lts, eqs, gts) = part f (f (xs ! (length xs div 2))) xs
in sort_key f lts @ eqs @ sort_key f gts)"
proof (cases xs) case Nil then show ?thesis by simp
next case (Cons _ ys) note hyps = Cons show ?thesis
proof (cases ys) case Nil with hyps show ?thesis by simp
next case (Cons _ zs) note hyps = hyps Cons show ?thesis
proof (cases zs) case Nil with hyps show ?thesis by auto
next case Cons
from sort_key_by_quicksort [of f xs]
have "sort_key f xs = (let (lts, eqs, gts) = part f (f (xs ! (length xs div 2))) xs
in sort_key f lts @ eqs @ sort_key f gts)"
by (simp only: split_def Let_def part_def fst_conv snd_conv)
with hyps Cons show ?thesis by (simp only: list.cases)
qed
qed
qed
end
hide_const (open) part
lemma sort_sorted_list_of_multiset_eq [simp]:
\<open>sort (sorted_list_of_multiset M) = sorted_list_of_multiset M\<close> for M :: \<open>'a::linorder multiset\<close>
by (rule properties_for_sort) simp_all
lemma mset_update: "i < length ls \<Longrightarrow> mset (ls[i := v]) = add_mset v (mset ls - {#ls ! i#})"
proof (induct ls arbitrary: i) case Nil then show ?case by simp
next case (Cons x xs)
show ?case
proof (cases i) case0 then show ?thesis by simp
next case (Suc i')
with Cons show ?thesis
by (cases \<open>x = xs ! i'\<close>) auto
qed
qed
lemma mset_swap: "i < length ls \<Longrightarrow> j < length ls \<Longrightarrow>
mset (ls[j := ls ! i, i := ls ! j]) = mset ls"
by (cases "i = j") (simp_all add: mset_update nth_mem_mset)
lemma mset_eq_finite:
\<open>finite {ys. mset ys = mset xs}\<close>
proof -
have \<open>{ys. mset ys = mset xs} \<subseteq> {ys. set ys \<subseteq> set xs \<and> length ys \<le> length xs}\<close>
by (auto simp add: dest: mset_eq_setD mset_eq_length)
moreover have \<open>finite {ys. set ys \<subseteq> set xs \<and> length ys \<le> length xs}\<close> using finite_lists_length_le by blast
ultimately show ?thesis
by (rule finite_subset)
qed
subsection \<open>The multiset order\<close>
definition mult1 :: "('a \<times> 'a) set \<Rightarrow> ('a multiset \<times> 'a multiset) set" where "mult1 r = {(N, M). \<exists>a M0 K. M = add_mset a M0 \<and> N = M0 + K \<and>
(\<forall>b. b \<in># K \<longrightarrow> (b, a) \<in> r)}"
definition mult :: "('a \<times> 'a) set \<Rightarrow> ('a multiset \<times> 'a multiset) set" where "mult r = (mult1 r)\<^sup>+"
definition multp :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool" where "multp r M N \<longleftrightarrow> (M, N) \<in> mult {(x, y). r x y}"
declare multp_def[pred_set_conv]
lemma mult1I:
assumes "M = add_mset a M0"and"N = M0 + K"and"\<And>b. b \<in># K \<Longrightarrow> (b, a) \<in> r"
shows "(N, M) \<in> mult1 r" using assms unfolding mult1_def by blast
lemma mult1E:
assumes "(N, M) \<in> mult1 r"
obtains a M0 K where "M = add_mset a M0""N = M0 + K""\<And>b. b \<in># K \<Longrightarrow> (b, a) \<in> r" using assms unfolding mult1_def by blast
lemma mono_mult1:
assumes "r \<subseteq> r'" shows "mult1 r \<subseteq> mult1 r'"
unfolding mult1_def using assms by blast
lemma mono_mult:
assumes "r \<subseteq> r'" shows "mult r \<subseteq> mult r'"
unfolding mult_def using mono_mult1[OF assms] trancl_mono by blast
lemma mono_multp[mono]: "r \<le> r' \<Longrightarrow> multp r \<le> multp r'"
unfolding le_fun_def le_bool_def
proof (intro allI impI)
fix M N :: "'a multiset"
assume "\<forall>x xa. r x xa \<longrightarrow> r' x xa"
hence "{(x, y). r x y} \<subseteq> {(x, y). r' x y}"
by blast
thus "multp r M N \<Longrightarrow> multp r' M N"
unfolding multp_def
by (fact mono_mult[THEN subsetD, rotated])
qed
lemma less_add:
assumes mult1: "(N, add_mset a M0) \<in> mult1 r"
shows "(\<exists>M. (M, M0) \<in> mult1 r \<and> N = add_mset a M) \<or>
(\<exists>K. (\<forall>b. b \<in># K \<longrightarrow> (b, a) \<in> r) \<and> N = M0 + K)"
proof -
let ?r = "\<lambda>K a. \<forall>b. b \<in># K \<longrightarrow> (b, a) \<in> r"
let ?R = "\<lambda>N M. \<exists>a M0 K. M = add_mset a M0 \<and> N = M0 + K \<and> ?r K a"
obtain a' M0' K where M0: "add_mset a M0 = add_mset a' M0'" and N: "N = M0' + K" and r: "?r K a'" using mult1 unfolding mult1_def by auto
show ?thesis (is "?case1 \<or> ?case2")
proof -
from M0 consider "M0 = M0'""a = a'"
| K' where "M0 = add_mset a' K'" "M0' = add_mset a K'"
by atomize_elim (simp only: add_eq_conv_ex)
then show ?thesis
proof cases case1
with N r have "?r K a \<and> N = M0 + K" by simp
then have ?case2 ..
then show ?thesis ..
next case2
from N 2(2) have n: "N = add_mset a (K' + K)" by simp
with r 2(1) have "?R (K' + K) M0" by blast
with n have ?case1 by (simp add: mult1_def)
then show ?thesis ..
qed
qed
qed
lemma all_accessible:
assumes "wf r"
shows "\<forall>M. M \<in> Wellfounded.acc (mult1 r)"
proof
let ?R = "mult1 r"
let ?W = "Wellfounded.acc ?R"
{
fix M M0 a
assume M0: "M0 \<in> ?W" and wf_hyp: "\<And>b. (b, a) \<in> r \<Longrightarrow> (\<forall>M \<in> ?W. add_mset b M \<in> ?W)" and acc_hyp: "\<forall>M. (M, M0) \<in> ?R \<longrightarrow> add_mset a M \<in> ?W"
have "add_mset a M0 \<in> ?W"
proof (rule accI [of "add_mset a M0"])
fix N
assume "(N, add_mset a M0) \<in> ?R"
then consider M where "(M, M0) \<in> ?R""N = add_mset a M"
| K where "\<forall>b. b \<in># K \<longrightarrow> (b, a) \<in> r""N = M0 + K"
by atomize_elim (rule less_add)
then show "N \<in> ?W"
proof cases case1
from acc_hyp have "(M, M0) \<in> ?R \<longrightarrow> add_mset a M \<in> ?W" ..
from thisand \<open>(M, M0) \<in> ?R\<close> have "add_mset a M \<in> ?W" ..
then show "N \<in> ?W" by (simp only: \<open>N = add_mset a M\<close>)
next case2
from this(1) have "M0 + K \<in> ?W"
proof (induct K) case empty
from M0 show "M0 + {#} \<in> ?W" by simp
next case (add x K)
from add.prems have "(x, a) \<in> r" by simp
with wf_hyp have "\<forall>M \<in> ?W. add_mset x M \<in> ?W" by blast
moreover from add have "M0 + K \<in> ?W" by simp
ultimately have "add_mset x (M0 + K) \<in> ?W" ..
then show "M0 + (add_mset x K) \<in> ?W" by simp
qed
then show "N \<in> ?W" by (simp only: 2(2))
qed
qed
} note tedious_reasoning = this
show "M \<in> ?W"for M
proof (induct M)
show "{#} \<in> ?W"
proof (rule accI)
fix b assume "(b, {#}) \<in> ?R"
with not_less_empty show "b \<in> ?W" by contradiction
qed
fix M a assume "M \<in> ?W"
from \<open>wf r\<close> have "\<forall>M \<in> ?W. add_mset a M \<in> ?W"
proof induct
fix a
assume r: "\<And>b. (b, a) \<in> r \<Longrightarrow> (\<forall>M \<in> ?W. add_mset b M \<in> ?W)"
show "\<forall>M \<in> ?W. add_mset a M \<in> ?W"
proof
fix M assume "M \<in> ?W"
then show "add_mset a M \<in> ?W"
by (rule acc_induct) (rule tedious_reasoning [OF _ r])
qed
qed
from thisand \<open>M \<in> ?W\<close> show "add_mset a M \<in> ?W" ..
qed
qed
lemma wf_mult1: "wf r \<Longrightarrow> wf (mult1 r)"
by (rule acc_wfI) (rule all_accessible)
lemma wf_mult: "wf r \<Longrightarrow> wf (mult r)"
unfolding mult_def by (rule wf_trancl) (rule wf_mult1)
lemma wfp_multp: "wfp r \<Longrightarrow> wfp (multp r)"
unfolding multp_def wfp_def
by (simp add: wf_mult)
text \<open>One direction.\<close>
lemma mult_implies_one_step:
assumes
trans: "trans r"and
MN: "(M, N) \<in> mult r"
shows "\<exists>I J K. N = I + J \<and> M = I + K \<and> J \<noteq> {#} \<and> (\<forall>k \<in> set_mset K. \<exists>j \<in> set_mset J. (k, j) \<in> r)" using MN unfolding mult_def mult1_def
proof (induction rule: converse_trancl_induct) case (base y)
then show ?case by force
next case (step y z) note yz = this(1) and zN = this(2) and N_decomp = this(3)
obtain I J K where
N: "N = I + J""z = I + K""J \<noteq> {#}""\<forall>k\<in>#K. \<exists>j\<in>#J. (k, j) \<in> r" using N_decomp by blast
obtain a M0 K' where
z: "z = add_mset a M0"and y: "y = M0 + K'"and K: "\<forall>b. b \<in># K' \<longrightarrow> (b, a) \<in> r" using yz by blast
show ?case
proof (cases "a \<in># K") caseTrue
moreover have "\<exists>j\<in>#J. (k, j) \<in> r"if"k \<in># K'"for k using K N trans True by (meson that transE)
ultimately show ?thesis
by (rule_tac x = I in exI, rule_tac x = J in exI, rule_tac x = "(K - {#a#}) + K'" in exI)
(use z y N in \<open>auto simp del: subset_mset.add_diff_assoc2 dest: in_diffD\<close>)
next caseFalse
then have "a \<in># I" by (metis N(2) union_iff union_single_eq_member z)
moreover have "M0 = I + K - {#a#}" using N(2) z by force
ultimately show ?thesis
by (rule_tac x = "I - {#a#}" in exI, rule_tac x = "add_mset a J" in exI,
rule_tac x = "K + K'" in exI)
(use z y N False K in \<open>auto simp: add.assoc\<close>)
qed
qed
lemma multp_implies_one_step: "transp R \<Longrightarrow> multp R M N \<Longrightarrow> \<exists>I J K. N = I + J \<and> M = I + K \<and> J \<noteq> {#} \<and> (\<forall>k\<in>#K. \<exists>x\<in>#J. R k x)"
by (rule mult_implies_one_step[to_pred])
lemma one_step_implies_mult:
assumes "J \<noteq> {#}"and "\<forall>k \<in> set_mset K. \<exists>j \<in> set_mset J. (k, j) \<in> r"
shows "(I + K, I + J) \<in> mult r" using assms
proof (induction "size J" arbitrary: I J K) case0
then show ?case by auto
next case (Suc n) note IH = this(1) and size_J = this(2)[THEN sym]
obtain J' a where J: "J = add_mset a J'" using size_J by (blast dest: size_eq_Suc_imp_eq_union)
show ?case
proof (cases "J' = {#}") caseTrue
then show ?thesis using J Suc by (fastforce simp add: mult_def mult1_def)
next case [simp]: False
have K: "K = {#x \<in># K. (x, a) \<in> r#} + {#x \<in># K. (x, a) \<notin> r#}"
by simp
have "(I + K, (I + {# x \<in># K. (x, a) \<in> r #}) + J') \<in> mult r" using IH[of J' "{# x \<in># K. (x, a) \<notin> r#}" "I + {# x \<in># K. (x, a) \<in> r#}"]
J Suc.prems K size_J by (auto simp: ac_simps)
moreover have "(I + {#x \<in># K. (x, a) \<in> r#} + J', I + J) \<in> mult r"
by (fastforce simp: J mult1_def mult_def)
ultimately show ?thesis
unfolding mult_def by simp
qed
qed
lemma one_step_implies_multp: "J \<noteq> {#} \<Longrightarrow> \<forall>k\<in>#K. \<exists>j\<in>#J. R k j \<Longrightarrow> multp R (I + K) (I + J)"
by (rule one_step_implies_mult[of _ _ "{(x, y). r x y}"for r, folded multp_def, simplified])
lemma subset_implies_mult:
assumes sub: "A \<subset># B"
shows "(A, B) \<in> mult r"
proof -
have ApBmA: "A + (B - A) = B" using sub by simp
have BmA: "B - A \<noteq> {#}" using sub by (simp add: Diff_eq_empty_iff_mset subset_mset.less_le_not_le)
thus ?thesis
by (rule one_step_implies_mult[of "B - A""{#}" _ A, unfolded ApBmA, simplified])
qed
lemma subset_implies_multp: "A \<subset># B \<Longrightarrow> multp r A B"
by (rule subset_implies_mult[of _ _ "{(x, y). r x y}"for r, folded multp_def])
lemma multp_repeat_mset_repeat_msetI:
assumes "transp R"and"multp R A B"and"n \<noteq> 0"
shows "multp R (repeat_mset n A) (repeat_mset n B)"
proof -
from \<open>transp R\<close> \<open>multp R A B\<close> obtain I J K where "B = I + J"and"A = I + K"and"J \<noteq> {#}"and"\<forall>k \<in># K. \<exists>x \<in># J. R k x"
by (auto dest: multp_implies_one_step)
have repeat_n_A_eq: "repeat_mset n A = repeat_mset n I + repeat_mset n K" using \<open>A = I + K\<close> by simp
have repeat_n_B_eq: "repeat_mset n B = repeat_mset n I + repeat_mset n J" using \<open>B = I + J\<close> by simp
show ?thesis
unfolding repeat_n_A_eq repeat_n_B_eq
proof (rule one_step_implies_multp)
from \<open>n \<noteq> 0\<close> show "repeat_mset n J \<noteq> {#}" using \<open>J \<noteq> {#}\<close>
by (simp add: repeat_mset_eq_empty_iff)
next
show "\<forall>k \<in># repeat_mset n K. \<exists>j \<in># repeat_mset n J. R k j" using \<open>\<forall>k \<in># K. \<exists>x \<in># J. R k x\<close>
by (metis count_greater_zero_iff nat_0_less_mult_iff repeat_mset.rep_eq)
qed
qed
subsubsection \<open>Monotonicity\<close>
lemma multp_mono_strong:
assumes "multp R M1 M2"and"transp R"and
S_if_R: "\<And>x y. x \<in> set_mset M1 \<Longrightarrow> y \<in> set_mset M2 \<Longrightarrow> R x y \<Longrightarrow> S x y"
shows "multp S M1 M2"
proof -
obtain I J K where "M2 = I + J"and"M1 = I + K"and"J \<noteq> {#}"and"\<forall>k\<in>#K. \<exists>x\<in>#J. R k x" using multp_implies_one_step[OF \<open>transp R\<close> \<open>multp R M1 M2\<close>] by auto
show ?thesis
unfolding \<open>M2 = I + J\<close> \<open>M1 = I + K\<close>
proof (rule one_step_implies_multp[OF \<open>J \<noteq> {#}\<close>])
show "\<forall>k\<in>#K. \<exists>j\<in>#J. S k j" using S_if_R
by (metis \<open>M1 = I + K\<close> \<open>M2 = I + J\<close> \<open>\<forall>k\<in>#K. \<exists>x\<in>#J. R k x\<close> union_iff)
qed
qed
lemma mult_mono_strong:
assumes "(M1, M2) \<in> mult r"and"trans r"and
S_if_R: "\<And>x y. x \<in> set_mset M1 \<Longrightarrow> y \<in> set_mset M2 \<Longrightarrow> (x, y) \<in> r \<Longrightarrow> (x, y) \<in> s"
shows "(M1, M2) \<in> mult s" using assms multp_mono_strong[of "\<lambda>x y. (x, y) \<in> r" M1 M2 "\<lambda>x y. (x, y) \<in> s",
unfolded multp_def transp_trans_eq, simplified]
by blast
from multp_implies_one_step[OF \<open>transp orda\<close> M1_lt_M2] obtain I J K where
M2_eq: "M2 = I + J"and
M1_eq: "M1 = I + K"and
J_neq_mempty: "J \<noteq> {#}"and
ball_K_less: "\<forall>k\<in>#K. \<exists>x\<in>#J. orda k x"
by metis
have "multp ordb (image_mset f I + image_mset f K) (image_mset f I + image_mset f J)"
proof (intro one_step_implies_multp ballI)
show "image_mset f J \<noteq> {#}" using J_neq_mempty by simp
next
fix k' assume "k'\<in>#image_mset f K"
then obtain k where "k' = f k"and k_in: "k \<in># K"
by auto
then obtain j where j_in: "j\<in>#J"and"orda k j" using ball_K_less by auto
have "ordb (f k) (f j)"
proof (rule \<open>monotone_on A orda ordb f\<close>[THEN monotone_onD, OF _ _ \<open>orda k j\<close>])
show "k \<in> A" using M1_eq M1_in k_in by auto
next
show "j \<in> A" using M2_eq M2_in j_in by auto
qed
thus "\<exists>j\<in>#image_mset f J. ordb k' j" using \<open>j \<in># J\<close> \<open>k' = f k\<close> by auto
qed
thus "multp ordb (image_mset f M1) (image_mset f M2)"
by (simp add: M1_eq M2_eq)
qed
lemma multp_image_mset_image_msetI:
assumes "multp (\<lambda>x y. R (f x) (f y)) M1 M2"and"transp R"
shows "multp R (image_mset f M1) (image_mset f M2)"
proof -
from \<open>transp R\<close> have "transp (\<lambda>x y. R (f x) (f y))"
by (auto intro: transpI dest: transpD)
with \<open>multp (\<lambda>x y. R (f x) (f y)) M1 M2\<close> obtain I J K where "M2 = I + J"and"M1 = I + K"and"J \<noteq> {#}"and"\<forall>k\<in>#K. \<exists>x\<in>#J. R (f k) (f x)" using multp_implies_one_step by blast
have "multp R (image_mset f I + image_mset f K) (image_mset f I + image_mset f J)"
proof (rule one_step_implies_multp)
show "image_mset f J \<noteq> {#}"
by (simp add: \<open>J \<noteq> {#}\<close>)
next
show "\<forall>k\<in>#image_mset f K. \<exists>j\<in>#image_mset f J. R k j"
by (simp add: \<open>\<forall>k\<in>#K. \<exists>x\<in>#J. R (f k) (f x)\<close>)
qed
thus ?thesis
by (simp add: \<open>M1 = I + K\<close> \<open>M2 = I + J\<close>)
qed
lemma multp_image_mset_image_msetD:
assumes "multp R (image_mset f A) (image_mset f B)"and "transp R"and
inj_on_f: "inj_on f (set_mset A \<union> set_mset B)"
shows "multp (\<lambda>x y. R (f x) (f y)) A B"
proof -
from assms(1,2) obtain I J K where
f_B_eq: "image_mset f B = I + J"and
f_A_eq: "image_mset f A = I + K"and
J_neq_mempty: "J \<noteq> {#}"and
ball_K_less: "\<forall>k\<in>#K. \<exists>x\<in>#J. R k x"
by (auto dest: multp_implies_one_step)
from f_B_eq obtain I' J' where
B_def: "B = I' + J'"and I_def: "I = image_mset f I'"and J_def: "J = image_mset f J'" using image_mset_eq_plusD by blast
from inj_on_f have inj_on_f': "inj_on f (set_mset A \<union> set_mset I')"
by (rule inj_on_subset) (auto simp add: B_def)
from f_A_eq obtain K' where
A_def: "A = I' + K'"and K_def: "K = image_mset f K'"
by (auto simp: I_def dest: image_mset_eq_image_mset_plusD[OF _ inj_on_f'])
show ?thesis
unfolding A_def B_def
proof (intro one_step_implies_multp ballI)
from J_neq_mempty show "J' \<noteq> {#}"
by (simp add: J_def)
next
fix k assume "k \<in># K'"
with ball_K_less obtain j' where "j' \<in># J" and "R (f k) j'" using K_def by auto
moreover then obtain j where "j \<in># J'"and"f j = j'" using J_def by auto
ultimately show "\<exists>j\<in>#J'. R (f k) (f j)"
by blast
qed
qed
subsubsection \<open>The multiset extension is cancellative for multiset union\<close>
lemma mult_cancel:
assumes "trans s"and"irrefl_on (set_mset Z) s"
shows "(X + Z, Y + Z) \<in> mult s \<longleftrightarrow> (X, Y) \<in> mult s" (is "?L \<longleftrightarrow> ?R")
proof
assume ?L thus ?R using \<open>irrefl_on (set_mset Z) s\<close>
proof (induct Z) case (add z Z)
obtain X' Y' Z' where *: "add_mset z X + Z = Z' + X'" "add_mset z Y + Z = Z' + Y'" "Y' \<noteq> {#}" "\<forall>x \<in> set_mset X'. \<exists>y \<in> set_mset Y'. (x, y) \<in> s" using mult_implies_one_step[OF \<open>trans s\<close> add(2)] by auto
consider Z2 where "Z' = add_mset z Z2" | X2 Y2 where "X' = add_mset z X2""Y' = add_mset z Y2" using *(1,2) by (metis add_mset_remove_trivial_If insert_iff set_mset_add_mset_insert union_iff)
thus ?case
proof (cases) case1 thus ?thesis using * one_step_implies_mult[of Y' X' s Z2] add(3)
by (auto simp: add.commute[of _ "{#_#}"] add.assoc intro: add(1) elim: irrefl_on_subset)
next case2 then obtain y where "y \<in> set_mset Y2""(z, y) \<in> s" using *(4) \<open>irrefl_on (set_mset (add_mset z Z)) s\<close>
by (auto simp: irrefl_on_def)
moreover from this transD[OF \<open>trans s\<close> _ this(2)]
have "x' \<in> set_mset X2 \<Longrightarrow> \<exists>y \<in> set_mset Y2. (x', y) \<in> s"for x' using2 *(4)[rule_format, of x'] by auto
ultimately show ?thesis using * one_step_implies_mult[of Y2 X2 s Z'] 2 add(3)
by (force simp: add.commute[of "{#_#}"] add.assoc[symmetric] intro: add(1)
elim: irrefl_on_subset)
qed
qed auto
next
assume ?R then obtain I J K
where "Y = I + J""X = I + K""J \<noteq> {#}""\<forall>k \<in> set_mset K. \<exists>j \<in> set_mset J. (k, j) \<in> s" using mult_implies_one_step[OF \<open>trans s\<close>] by blast
thus ?L using one_step_implies_mult[of J K s "I + Z"] by (auto simp: ac_simps)
qed
lemma multp_cancel: "transp R \<Longrightarrow> irreflp_on (set_mset Z) R \<Longrightarrow> multp R (X + Z) (Y + Z) \<longleftrightarrow> multp R X Y"
by (rule mult_cancel[to_pred])
lemma mult_cancel_add_mset: "trans r \<Longrightarrow> irrefl_on {z} r \<Longrightarrow>
((add_mset z X, add_mset z Y) \<in> mult r) = ((X, Y) \<in> mult r)"
by (rule mult_cancel[of _ "{#_#}", simplified])
lemma multp_cancel_add_mset: "transp R \<Longrightarrow> irreflp_on {z} R \<Longrightarrow> multp R (add_mset z X) (add_mset z Y) = multp R X Y"
by (rule mult_cancel_add_mset[to_pred, folded bot_set_def])
lemma mult_cancel_max0:
assumes "trans s"and"irrefl_on (set_mset X \<inter> set_mset Y) s"
shows "(X, Y) \<in> mult s \<longleftrightarrow> (X - X \<inter># Y, Y - X \<inter># Y) \<in> mult s" (is "?L \<longleftrightarrow> ?R")
proof -
have "(X - X \<inter># Y + X \<inter># Y, Y - X \<inter># Y + X \<inter># Y) \<in> mult s \<longleftrightarrow> (X - X \<inter># Y, Y - X \<inter># Y) \<in> mult s"
proof (rule mult_cancel)
from assms show "trans s"
by simp
next
from assms show "irrefl_on (set_mset (X \<inter># Y)) s"
by simp
qed
moreover have "X - X \<inter># Y + X \<inter># Y = X""Y - X \<inter># Y + X \<inter># Y = Y"
by (auto simp flip: count_inject)
ultimately show ?thesis
by simp
qed
lemma mult_cancel_max: "trans r \<Longrightarrow> irrefl_on (set_mset X \<inter> set_mset Y) r \<Longrightarrow>
(X, Y) \<in> mult r \<longleftrightarrow> (X - Y, Y - X) \<in> mult r"
by (rule mult_cancel_max0[simplified])
lemma multp_cancel_max: "transp R \<Longrightarrow> irreflp_on (set_mset X \<inter> set_mset Y) R \<Longrightarrow> multp R X Y \<longleftrightarrow> multp R (X - Y) (Y - X)"
by (rule mult_cancel_max[to_pred])
lemma mult1_lessE:
assumes "(N, M) \<in> mult1 {(a, b). r a b}"and"asymp r"
obtains a M0 K where "M = add_mset a M0""N = M0 + K" "a \<notin># K""\<And>b. b \<in># K \<Longrightarrow> r b a"
proof -
from assms obtain a M0 K where "M = add_mset a M0""N = M0 + K"and
*: "b \<in># K \<Longrightarrow> r b a"for b by (blast elim: mult1E)
moreover from * [of a] have "a \<notin># K" using \<open>asymp r\<close> by (meson asympD)
ultimately show thesis by (auto intro: that)
qed
lemma trans_on_mult:
assumes "trans_on A r"and"\<And>M. M \<in> B \<Longrightarrow> set_mset M \<subseteq> A"
shows "trans_on B (mult r)" using assms by (metis mult_def subset_UNIV trans_on_subset trans_trancl)
lemma trans_mult: "trans r \<Longrightarrow> trans (mult r)" using trans_on_mult[of UNIV r UNIV, simplified] .
lemma transp_on_multp:
assumes "transp_on A r"and"\<And>M. M \<in> B \<Longrightarrow> set_mset M \<subseteq> A"
shows "transp_on B (multp r)"
by (metis mult_def multp_def transD trans_trancl transp_onI)
lemma transp_multp: "transp r \<Longrightarrow> transp (multp r)" using transp_on_multp[of UNIV r UNIV, simplified] .
lemma irrefl_mult:
assumes "trans r""irrefl r"
shows "irrefl (mult r)"
proof (intro irreflI notI)
fix M
assume "(M, M) \<in> mult r"
then obtain I J K where "M = I + J"and"M = I + K" and"J \<noteq> {#}"and"(\<forall>k\<in>set_mset K. \<exists>j\<in>set_mset J. (k, j) \<in> r)" using mult_implies_one_step[OF \<open>trans r\<close>] by blast
then have *: "K \<noteq> {#}"and **: "\<forall>k\<in>set_mset K. \<exists>j\<in>set_mset K. (k, j) \<in> r" by auto
have "finite (set_mset K)" by simp
hence "set_mset K = {}" using **
proof (induction rule: finite_induct) case empty
thus ?case by simp
next case (insert x F)
have False using \<open>irrefl r\<close>[unfolded irrefl_def, rule_format] using \<open>trans r\<close>[THEN transD]
by (metis equals0D insert.IH insert.prems insertE insertI1 insertI2)
thus ?case ..
qed
with * show False by simp
qed
lemma irreflp_multp: "transp R \<Longrightarrow> irreflp R \<Longrightarrow> irreflp (multp R)"
by (rule irrefl_mult[of "{(x, y). r x y}"for r,
folded transp_trans_eq irreflp_irrefl_eq, simplified, folded multp_def])
instantiation multiset :: (preorder) order begin
definition less_multiset :: "'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool"
where "M < N \<longleftrightarrow> multp (<) M N"
definition less_eq_multiset :: "'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool"
where "less_eq_multiset M N \<longleftrightarrow> M < N \<or> M = N"
instance
proof intro_classes
fix M N :: "'a multiset"
show "(M < N) = (M \<le> N \<and> \<not> N \<le> M)"
unfolding less_eq_multiset_def less_multiset_def
by (metis irreflp_def irreflp_on_less irreflp_multp transpE transp_on_less transp_multp)
next
fix M :: "'a multiset"
show "M \<le> M"
unfolding less_eq_multiset_def
by simp
next
fix M1 M2 M3 :: "'a multiset"
show "M1 \<le> M2 \<Longrightarrow> M2 \<le> M3 \<Longrightarrow> M1 \<le> M3"
unfolding less_eq_multiset_def less_multiset_def using transp_multp[OF transp_on_less, THEN transpD]
by blast
next
fix M N :: "'a multiset"
show "M \<le> N \<Longrightarrow> N \<le> M \<Longrightarrow> M = N"
unfolding less_eq_multiset_def less_multiset_def using transp_multp[OF transp_on_less, THEN transpD] using irreflp_multp[OF transp_on_less irreflp_on_less, unfolded irreflp_def, rule_format]
by blast
qed
end
lemma mset_le_irrefl [elim!]:
fixes M :: "'a::preorder multiset"
shows "M < M \<Longrightarrow> R"
by simp
lemma wfp_less_multiset[simp]:
assumes wf: "wfp ((<) :: ('a :: preorder) \<Rightarrow> 'a \<Rightarrow> bool)"
shows "wfp ((<) :: 'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool)"
unfolding less_multiset_def using wfp_multp[OF wf] .
lemma total_on_mult:
assumes "total_on A r"and"trans r"and"\<And>M. M \<in> B \<Longrightarrow> set_mset M \<subseteq> A"
shows "total_on B (mult r)"
proof (rule total_onI)
fix M1 M2 assume "M1 \<in> B"and"M2 \<in> B"and"M1 \<noteq> M2"
let ?I = "M1 \<inter># M2"
show "(M1, M2) \<in> mult r \<or> (M2, M1) \<in> mult r"
proof (cases "M1 - ?I = {#} \<or> M2 - ?I = {#}") caseTrue
with \<open>M1 \<noteq> M2\<close> show ?thesis
by (metis Diff_eq_empty_iff_mset diff_intersect_left_idem diff_intersect_right_idem
subset_implies_mult subset_mset.less_le)
next caseFalse
from assms(1) have "total_on (set_mset (M1 - ?I)) r"
by (meson \<open>M1 \<in> B\<close> assms(3) diff_subset_eq_self set_mset_mono total_on_subset)
with False obtain greatest1 where
greatest1_in: "greatest1 \<in># M1 - ?I"and
greatest1_greatest: "\<forall>x \<in># M1 - ?I. greatest1 \<noteq> x \<longrightarrow> (x, greatest1) \<in> r" using Multiset.bex_greatest_element[to_set, of "M1 - ?I" r]
by (metis assms(2) subset_UNIV trans_on_subset)
from assms(1) have "total_on (set_mset (M2 - ?I)) r"
by (meson \<open>M2 \<in> B\<close> assms(3) diff_subset_eq_self set_mset_mono total_on_subset)
with False obtain greatest2 where
greatest2_in: "greatest2 \<in># M2 - ?I"and
greatest2_greatest: "\<forall>x \<in># M2 - ?I. greatest2 \<noteq> x \<longrightarrow> (x, greatest2) \<in> r" using Multiset.bex_greatest_element[to_set, of "M2 - ?I" r]
by (metis assms(2) subset_UNIV trans_on_subset)
have "greatest1 \<noteq> greatest2" using greatest1_in \<open>greatest2 \<in># M2 - ?I\<close>
by (metis diff_intersect_left_idem diff_intersect_right_idem dual_order.eq_iff in_diff_count
in_diff_countE le_add_same_cancel2 less_irrefl zero_le)
hence "(greatest1, greatest2) \<in> r \<or> (greatest2, greatest1) \<in> r" using \<open>total_on A r\<close>[unfolded total_on_def, rule_format, of greatest1 greatest2]
\<open>M1 \<in> B\<close> \<open>M2 \<in> B\<close> greatest1_in greatest2_in assms(3)
by (meson in_diffD in_mono)
thus ?thesis
proof (elim disjE)
assume "(greatest1, greatest2) \<in> r"
have "(?I + (M1 - ?I), ?I + (M2 - ?I)) \<in> mult r"
proof (rule one_step_implies_mult[of "M2 - ?I""M1 - ?I" r ?I])
show "M2 - ?I \<noteq> {#}" usingFalse by force
next
show "\<forall>k\<in>#M1 - ?I. \<exists>j\<in>#M2 - ?I. (k, j) \<in> r" using \<open>(greatest1, greatest2) \<in> r\<close> greatest2_in greatest1_greatest
by (metis assms(2) transD)
qed
hence "(M1, M2) \<in> mult r"
by (metis subset_mset.add_diff_inverse subset_mset.inf.cobounded1
subset_mset.inf.cobounded2)
thus "(M1, M2) \<in> mult r \<or> (M2, M1) \<in> mult r" ..
next
assume "(greatest2, greatest1) \<in> r"
have "(?I + (M2 - ?I), ?I + (M1 - ?I)) \<in> mult r"
proof (rule one_step_implies_mult[of "M1 - ?I""M2 - ?I" r ?I])
show "M1 - M1 \<inter># M2 \<noteq> {#}" usingFalse by force
next
show "\<forall>k\<in>#M2 - ?I. \<exists>j\<in>#M1 - ?I. (k, j) \<in> r" using \<open>(greatest2, greatest1) \<in> r\<close> greatest1_in greatest2_greatest
by (metis assms(2) transD)
qed
hence "(M2, M1) \<in> mult r"
by (metis subset_mset.add_diff_inverse subset_mset.inf.cobounded1
subset_mset.inf.cobounded2)
thus "(M1, M2) \<in> mult r \<or> (M2, M1) \<in> mult r" ..
qed
qed
qed
lemma total_mult: "total r \<Longrightarrow> trans r \<Longrightarrow> total (mult r)"
by (rule total_on_mult[of UNIV r UNIV, simplified])
lemma totalp_on_multp: "totalp_on A R \<Longrightarrow> transp R \<Longrightarrow> (\<And>M. M \<in> B \<Longrightarrow> set_mset M \<subseteq> A) \<Longrightarrow> totalp_on B (multp R)" using total_on_mult[of A "{(x,y). R x y}" B, to_pred]
by (simp add: multp_def total_on_def totalp_on_def)
lemma totalp_multp: "totalp R \<Longrightarrow> transp R \<Longrightarrow> totalp (multp R)"
by (rule totalp_on_multp[of UNIV R UNIV, simplified])
subsection \<open>Quasi-executable version of the multiset extension\<close>
text \<open>
Predicate variants of \<open>mult\<close> and the reflexive closure of \<open>mult\<close>, which are
executable whenever the given predicate \<open>P\<close> is. Together with the standard
code equations for \<open>(\<inter>#\<close>) and \<open>(-\<close>) this should yield quadratic
(with respect to calls to \<open>P\<close>) implementations of \<open>multp_code\<close> and \<open>multeqp_code\<close>.
\<close>
definition multp_code :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool" where "multp_code P N M =
(let Z = M \<inter># N; X = M - Z in
X \<noteq> {#} \<and> (let Y = N - Z in (\<forall>y \<in> set_mset Y. \<exists>x \<in> set_mset X. P y x)))"
definition multeqp_code :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a multiset \<Rightarrow> 'a multiset \<Rightarrow> bool" where "multeqp_code P N M =
(let Z = M \<inter># N; X = M - Z; Y = N - Z in
(\<forall>y \<in> set_mset Y. \<exists>x \<in> set_mset X. P y x))"
lemma multp_code_iff_mult:
assumes "irrefl_on (set_mset N \<inter> set_mset M) R"and"trans R"and
[simp]: "\<And>x y. P x y \<longleftrightarrow> (x, y) \<in> R"
shows "multp_code P N M \<longleftrightarrow> (N, M) \<in> mult R" (is "?L \<longleftrightarrow> ?R")
proof -
have *: "M \<inter># N + (N - M \<inter># N) = N""M \<inter># N + (M - M \<inter># N) = M" "(M - M \<inter># N) \<inter># (N - M \<inter># N) = {#}" by (auto simp flip: count_inject)
show ?thesis
proof
assume ?L thus ?R using one_step_implies_mult[of "M - M \<inter># N""N - M \<inter># N" R "M \<inter># N"] *
by (auto simp: multp_code_def Let_def)
next
have [dest!]: "I = {#}"if"(I + J) \<inter># (I + K) = {#}"for I J K using that by (metis inter_union_distrib_right union_eq_empty)
assume ?R thus ?L
using mult_cancel_max
using mult_implies_one_step[OF assms(2), of "N - M \<inter># N" "M - M \<inter># N"]
mult_cancel_max[OF assms(2,1)] * by (auto simp: multp_code_def)
qed
qed
lemma multp_code_iff_multp:
"irreflp_on (set_mset M \<inter> set_mset N) R \<Longrightarrow> transp R \<Longrightarrow> multp_code R M N \<longleftrightarrow> multp R M N"
using multp_code_iff_mult[simplified, to_pred, of M N R R] by simp
lemma multp_code_eq_multp:
assumes "irreflp R" and "transp R"
shows "multp_code R = multp R"
proof (intro ext)
fix M N
show "multp_code R M N = multp R M N"
proof (rule multp_code_iff_multp)
from assms show "irreflp_on (set_mset M \<inter> set_mset N) R"
by (auto intro: irreflp_on_subset)
next
from assms show "transp R"
by simp
qed
qed
lemma multeqp_code_iff_reflcl_mult:
assumes "irrefl_on (set_mset N \<inter> set_mset M) R" and "trans R" and "\<And>x y. P x y \<longleftrightarrow> (x, y) \<in> R"
shows "multeqp_code P N M \<longleftrightarrow> (N, M) \<in> (mult R)\<^sup>="
proof -
have "\<exists>y. count M y < count N y" if "N \<noteq> M" "M - M \<inter># N = {#}"
proof -
from that obtain y where "count N y \<noteq> count M y"
by (auto simp flip: count_inject)
then show ?thesis
using \<open>M - M \<inter># N = {#}\<close>
by (auto simp flip: count_inject dest!: le_neq_implies_less fun_cong[of _ _ y])
qed
then have "multeqp_code P N M \<longleftrightarrow> multp_code P N M \<or> N = M"
by (auto simp: multeqp_code_def multp_code_def Let_def in_diff_count)
thus ?thesis
using multp_code_iff_mult[OF assms] by simp
qed
lemma multeqp_code_iff_reflclp_multp:
"irreflp_on (set_mset M \<inter> set_mset N) R \<Longrightarrow> transp R \<Longrightarrow> multeqp_code R M N \<longleftrightarrow> (multp R)\<^sup>=\<^sup>= M N"
using multeqp_code_iff_reflcl_mult[simplified, to_pred, of M N R R] by simp
lemma multeqp_code_eq_reflclp_multp:
assumes "irreflp R" and "transp R"
shows "multeqp_code R = (multp R)\<^sup>=\<^sup>="
proof (intro ext)
fix M N
show "multeqp_code R M N \<longleftrightarrow> (multp R)\<^sup>=\<^sup>= M N"
proof (rule multeqp_code_iff_reflclp_multp)
from assms show "irreflp_on (set_mset M \<inter> set_mset N) R"
by (auto intro: irreflp_on_subset)
next
from assms show "transp R"
by simp
qed
qed
subsubsection \<open>Monotonicity of multiset union\<close>
lemma mult1_union: "(B, D) \<in> mult1 r \<Longrightarrow> (C + B, C + D) \<in> mult1 r"
by (force simp: mult1_def)
lemma union_le_mono2: "B < D \<Longrightarrow> C + B < C + (D::'a::preorder multiset)"
unfolding less_multiset_def multp_def mult_def
by (induction rule: trancl_induct; blast intro: mult1_union trancl_trans)
lemma union_le_mono1: "B < D \<Longrightarrow> B + C < D + (C::'a::preorder multiset)"
by (metis add.commute union_le_mono2)
lemma union_less_mono:
fixes A B C D :: "'a::preorder multiset"
shows "A < C \<Longrightarrow> B < D \<Longrightarrow> A + B < C + D"
by (blast intro!: union_le_mono1 union_le_mono2 less_trans)
instantiation multiset :: (preorder) ordered_ab_semigroup_add
begin
instance
by standard (auto simp add: less_eq_multiset_def intro: union_le_mono2)
end
subsubsection \<open>Termination proofs with multiset orders\<close>
lemma multi_member_skip: "x \<in># XS \<Longrightarrow> x \<in># {# y #} + XS"
and multi_member_this: "x \<in># {# x #} + XS"
and multi_member_last: "x \<in># {# x #}"
by auto
lemma smsI:
"(set_mset A, set_mset B) \<in> max_strict \<Longrightarrow> (Z + A, Z + B) \<in> ms_strict"
unfolding ms_strict_def
by (rule one_step_implies_mult) (auto simp add: max_strict_def pair_less_def elim!:max_ext.cases)
lemma wmsI:
"(set_mset A, set_mset B) \<in> max_strict \<or> A = {#} \<and> B = {#}
\<Longrightarrow> (Z + A, Z + B) \<in> ms_weak"
unfolding ms_weak_def ms_strict_def
by (auto simp add: pair_less_def max_strict_def elim!:max_ext.cases intro: one_step_implies_mult)
inductive pw_leq
where
pw_leq_empty: "pw_leq {#} {#}"
| pw_leq_step: "\<lbrakk>(x,y) \<in> pair_leq; pw_leq X Y \<rbrakk> \<Longrightarrow> pw_leq ({#x#} + X) ({#y#} + Y)"
lemma pw_leq_split:
assumes "pw_leq X Y"
shows "\<exists>A B Z. X = A + Z \<and> Y = B + Z \<and> ((set_mset A, set_mset B) \<in> max_strict \<or> (B = {#} \<and> A = {#}))"
using assms
proof induct
case pw_leq_empty thus ?case by auto
next
case (pw_leq_step x y X Y)
then obtain A B Z where
[simp]: "X = A + Z" "Y = B + Z"
and 1[simp]: "(set_mset A, set_mset B) \<in> max_strict \<or> (B = {#} \<and> A = {#})"
by auto
from pw_leq_step consider "x = y" | "(x, y) \<in> pair_less"
unfolding pair_leq_def by auto
thus ?case
proof cases
case [simp]: 1
have "{#x#} + X = A + ({#y#}+Z) \<and> {#y#} + Y = B + ({#y#}+Z) \<and>
((set_mset A, set_mset B) \<in> max_strict \<or> (B = {#} \<and> A = {#}))"
by auto
thus ?thesis by blast
next
case 2
let ?A' = "{#x#} + A" and ?B' = "{#y#} + B"
have "{#x#} + X = ?A' + Z"
"{#y#} + Y = ?B' + Z"
by auto
moreover have
"(set_mset ?A', set_mset ?B') \<in> max_strict"
using 12 unfolding max_strict_def
by (auto elim!: max_ext.cases)
ultimately show ?thesis by blast
qed
qed
lemma
assumes pwleq: "pw_leq Z Z'"
shows ms_strictI: "(set_mset A, set_mset B) \<in> max_strict \<Longrightarrow> (Z + A, Z' + B) \<in> ms_strict"
and ms_weakI1: "(set_mset A, set_mset B) \<in> max_strict \<Longrightarrow> (Z + A, Z' + B) \<in> ms_weak"
and ms_weakI2: "(Z + {#}, Z' + {#}) \<in> ms_weak"
proof -
from pw_leq_split[OF pwleq]
obtain A' B' Z''
where [simp]: "Z = A' + Z''" "Z' = B' + Z''"
and mx_or_empty: "(set_mset A', set_mset B') \<in> max_strict \<or> (A' = {#} \<and> B' = {#})"
by blast
{
assume max: "(set_mset A, set_mset B) \<in> max_strict"
from mx_or_empty
have "(Z'' + (A + A'), Z'' + (B + B')) \<in> ms_strict"
proof
assume max': "(set_mset A', set_mset B') \<in> max_strict"
with max have "(set_mset (A + A'), set_mset (B + B')) \<in> max_strict"
by (auto simp: max_strict_def intro: max_ext_additive)
thus ?thesis by (rule smsI)
next
assume [simp]: "A' = {#} \<and> B' = {#}"
show ?thesis by (rule smsI) (auto intro: max)
qed
thus "(Z + A, Z' + B) \<in> ms_strict" by (simp add: ac_simps)
thus "(Z + A, Z' + B) \<in> ms_weak" by (simp add: ms_weak_def)
}
from mx_or_empty
have "(Z'' + A', Z'' + B') \<in> ms_weak" by (rule wmsI)
thus "(Z + {#}, Z' + {#}) \<in> ms_weak" by (simp add: ac_simps)
qed
lemma empty_neutral: "{#} + x = x" "x + {#} = x"
and nonempty_plus: "{# x #} + rs \<noteq> {#}"
and nonempty_single: "{# x #} \<noteq> {#}"
by auto
setup \<open>
let
fun msetT T = \<^Type>\<open>multiset T\<close>;
fun mk_mset T [] = \<^instantiate>\<open>'a = T in term \<open>{#}\<close>\<close>
| mk_mset T [x] = \<^instantiate>\<open>'a = T and x in term \<open>{#x#}\<close>\<close>
| mk_mset T (x :: xs) = \<^Const>\<open>plus \<open>msetT T\<close> for \<open>mk_mset T [x]\<close> \<open>mk_mset T xs\<close>\<close>
fun mset_member_tac ctxt m i =
if m <= 0 then
resolve_tac ctxt @{thms multi_member_this} i ORELSE
resolve_tac ctxt @{thms multi_member_last} i
else
resolve_tac ctxt @{thms multi_member_skip} i THEN mset_member_tac ctxt (m - 1) i
lemma union_right_cancel: "M + K = N + K \<longleftrightarrow> M = (N::'a multiset)"
by (fact add_right_cancel)
lemma union_left_cancel: "K + M = K + N \<longleftrightarrow> M = (N::'a multiset)"
by (fact add_left_cancel)
lemma multi_union_self_other_eq: "(A::'a multiset) + X = A + Y \<Longrightarrow> X = Y"
by (fact add_left_imp_eq)
lemma mset_subset_trans: "(M::'a multiset) \<subset># K \<Longrightarrow> K \<subset># N \<Longrightarrow> M \<subset># N"
by (fact subset_mset.less_trans)
lemma multiset_inter_commute: "A \<inter># B = B \<inter># A"
by (fact subset_mset.inf.commute)
lemma multiset_inter_assoc: "A \<inter># (B \<inter># C) = A \<inter># B \<inter># C"
by (fact subset_mset.inf.assoc [symmetric])
lemma multiset_inter_left_commute: "A \<inter># (B \<inter># C) = B \<inter># (A \<inter># C)"
by (fact subset_mset.inf.left_commute)
lemma mset_le_not_refl: "\<not> M < (M::'a::preorder multiset)"
by (fact less_irrefl)
lemma mset_le_trans: "K < M \<Longrightarrow> M < N \<Longrightarrow> K < (N::'a::preorder multiset)"
by (fact less_trans)
lemma mset_le_not_sym: "M < N \<Longrightarrow> \<not> N < (M::'a::preorder multiset)"
by (fact less_not_sym)
lemma mset_le_asym: "M < N \<Longrightarrow> (\<not> P \<Longrightarrow> N < (M::'a::preorder multiset)) \<Longrightarrow> P"
by (fact less_asym)
declaration \<open>
let
fun multiset_postproc _ maybe_name all_values (T as Type (_, [elem_T])) (Const _ $ t') =
let
val (maybe_opt, ps) =
Nitpick_Model.dest_plain_fun t'
||> (~~)
||> map (apsnd (snd o HOLogic.dest_number))
fun elems_for t =
(case AList.lookup (=) ps t of
SOME n => replicate n t
| NONE => [Const (maybe_name, elem_T --> elem_T) $ t])
in
(case maps elems_for (all_values elem_T) @
(if maybe_opt then [Const (Nitpick_Model.unrep_mixfix (), elem_T)] else []) of
[] => \<^Const>\<open>Groups.zero T\<close>
| ts => foldl1 (fn (s, t) => \<^Const>\<open>add_mset elem_T for s t\<close>) ts)
end
| multiset_postproc _ _ _ _ t = t
in Nitpick_Model.register_term_postprocessor \<^typ>\<open>'a multiset\<close> multiset_postproc end
\<close>
subsection \<open>Naive implementation using lists\<close>
code_datatype mset
lemma [code]: "{#} = mset []"
by simp
lemma [code]: "add_mset x (mset xs) = mset (x # xs)"
by simp
lemma [code]:
"mset xs \<inter># mset ys =
mset (snd (fold (\<lambda>x (ys, zs).
if x \<in> set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, [])))"
proof -
have "\<And>zs. mset (snd (fold (\<lambda>x (ys, zs).
if x \<in> set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, zs))) =
(mset xs \<inter># mset ys) + mset zs"
by (induct xs arbitrary: ys)
(auto simp add: inter_add_right1 inter_add_right2 ac_simps)
then show ?thesis by simp
qed
lemma [code]:
"mset xs \<union># mset ys =
mset (case_prod append (fold (\<lambda>x (ys, zs). (remove1 x ys, x # zs)) xs (ys, [])))"
proof -
have "\<And>zs. mset (case_prod append (fold (\<lambda>x (ys, zs). (remove1 x ys, x # zs)) xs (ys, zs))) =
(mset xs \<union># mset ys) + mset zs"
by (induct xs arbitrary: ys) (simp_all add: multiset_eq_iff)
then show ?thesis by simp
qed
declare in_multiset_in_set [code_unfold]
lemma [code]: "count (mset xs) x = fold (\<lambda>y. if x = y then Suc else id) xs 0"
proof -
have "\<And>n. fold (\<lambda>y. if x = y then Suc else id) xs n = count (mset xs) x + n"
by (induct xs) simp_all
then show ?thesis by simp
qed
declare set_mset_mset [code]
declare sorted_list_of_multiset_mset [code]
lemma [code]: \<comment> \<open>not very efficient, but representation-ignorant!\<close>
"mset_set A = mset (sorted_list_of_set A)"
by (metis mset_sorted_list_of_multiset sorted_list_of_mset_set)
declare size_mset [code]
fun subset_eq_mset_impl :: "'a list \<Rightarrow> 'a list \<Rightarrow> bool option" where
"subset_eq_mset_impl [] ys = Some (ys \<noteq> [])"
| "subset_eq_mset_impl (Cons x xs) ys = (case List.extract ((=) x) ys of
None \<Rightarrow> None
| Some (ys1,_,ys2) \<Rightarrow> subset_eq_mset_impl xs (ys1 @ ys2))"
lemma subset_eq_mset_impl: "(subset_eq_mset_impl xs ys = None \<longleftrightarrow> \<not> mset xs \<subseteq># mset ys) \<and>
(subset_eq_mset_impl xs ys = Some True \<longleftrightarrow> mset xs \<subset># mset ys) \<and>
(subset_eq_mset_impl xs ys = Some False \<longrightarrow> mset xs = mset ys)"
proof (induct xs arbitrary: ys)
case (Nil ys)
show ?case by (auto simp: subset_mset.zero_less_iff_neq_zero)
next
case (Cons x xs ys)
show ?case
proof (cases "List.extract ((=) x) ys")
case None
hence x: "x \<notin> set ys" by (simp add: extract_None_iff)
have nle: False if "mset (x # xs) \<subseteq># mset ys"
using set_mset_mono[OF that] x by simp
moreover
have False if "mset (x # xs) \<subset># mset ys"
proof -
from that have "mset (x # xs) \<subseteq># mset ys" by auto
from nle[OF this] show ?thesis .
qed
ultimately show ?thesis using None by auto
next
case (Some res)
obtain ys1 y ys2 where res: "res = (ys1,y,ys2)" by (cases res, auto)
note Some = Some[unfolded res]
from extract_SomeE[OF Some] have "ys = ys1 @ x # ys2" by simp
hence id: "mset ys = add_mset x (mset (ys1 @ ys2))"
by auto
show ?thesis unfolding subset_eq_mset_impl.simps
by (simp add: Some id Cons)
qed
qed
lemma [code]: "mset xs \<subset># mset ys \<longleftrightarrow> subset_eq_mset_impl xs ys = Some True"
using subset_eq_mset_impl by blast
instantiation multiset :: (equal) equal
begin
definition
[code del]: "HOL.equal A (B :: 'a multiset) \<longleftrightarrow> A = B"
lemma [code]: "HOL.equal (mset xs) (mset ys) \<longleftrightarrow> subset_eq_mset_impl xs ys = Some False"
unfolding equal_multiset_def
using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto)
instance
by standard (simp add: equal_multiset_def)
end
declare sum_mset_sum_list [code]
lemma [code]: "prod_mset (mset xs) = fold times xs 1"
proof -
have "\<And>x. fold times xs x = prod_mset (mset xs) * x"
by (induct xs) (simp_all add: ac_simps)
then show ?thesis by simp
qed
text \<open>
Exercise for the casual reader: add implementations for \<^term>\<open>(\<le>)\<close>
and \<^term>\<open>(<)\<close> (multiset order).
\<close>
text \<open>Quickcheck generators\<close>
context
includes term_syntax
begin
definition
msetify :: "'a::typerep list \<times> (unit \<Rightarrow> Code_Evaluation.term)
\<Rightarrow> 'a multiset \<times> (unit \<Rightarrow> Code_Evaluation.term)" where
[code_unfold]: "msetify xs = Code_Evaluation.valtermify mset {\<cdot>} xs"
end
instantiation multiset :: (random) random
begin
context
includes state_combinator_syntax
begin
definition
"Quickcheck_Random.random i = Quickcheck_Random.random i \<circ>\<rightarrow> (\<lambda>xs. Pair (msetify xs))"
instance ..
end
end
instantiation multiset :: (full_exhaustive) full_exhaustive
begin
definition full_exhaustive_multiset :: "('a multiset \<times> (unit \<Rightarrow> term) \<Rightarrow> (bool \<times> term list) option) \<Rightarrow> natural \<Rightarrow> (bool \<times> term list) option"
where
"full_exhaustive_multiset f i = Quickcheck_Exhaustive.full_exhaustive (\<lambda>xs. f (msetify xs)) i"
instance ..
end
hide_const (open) msetify
subsection \<open>BNF setup\<close>
definition rel_mset where
"rel_mset R X Y \<longleftrightarrow> (\<exists>xs ys. mset xs = X \<and> mset ys = Y \<and> list_all2 R xs ys)"
lemma mset_zip_take_Cons_drop_twice:
assumes "length xs = length ys" "j \<le> length xs"
shows "mset (zip (take j xs @ x # drop j xs) (take j ys @ y # drop j ys)) =
add_mset (x,y) (mset (zip xs ys))"
using assms
proof (induct xs ys arbitrary: x y j rule: list_induct2)
case Nil
thus ?case
by simp
next
case (Cons x xs y ys)
thus ?case
proof (cases "j = 0")
case True
thus ?thesis
by simp
next
case False
then obtain k where k: "j = Suc k"
by (cases j) simp
hence "k \<le> length xs"
using Cons.prems by auto
hence "mset (zip (take k xs @ x # drop k xs) (take k ys @ y # drop k ys)) =
add_mset (x,y) (mset (zip xs ys))"
by (rule Cons.hyps(2))
thus ?thesis
unfolding k by auto
qed
qed
lemma ex_mset_zip_left:
assumes "length xs = length ys" "mset xs' = mset xs"
shows "\<exists>ys'. length ys' = length xs' \<and> mset (zip xs' ys') = mset (zip xs ys)"
using assms
proof (induct xs ys arbitrary: xs' rule: list_induct2)
case Nil
thus ?case
by auto
next
case (Cons x xs y ys xs')
obtain j where j_len: "j < length xs'" and nth_j: "xs' ! j = x"
by (metis Cons.prems in_set_conv_nth list.set_intros(1) mset_eq_setD)
define xsa where "xsa = take j xs' @ drop (Suc j) xs'"
have "mset xs' = {#x#} + mset xsa"
unfolding xsa_def using j_len nth_j
by (metis Cons_nth_drop_Suc union_mset_add_mset_right add_mset_remove_trivial add_diff_cancel_left'
append_take_drop_id mset.simps(2) mset_append)
hence ms_x: "mset xsa = mset xs"
by (simp add: Cons.prems)
then obtain ysa where
len_a: "length ysa = length xsa" and ms_a: "mset (zip xsa ysa) = mset (zip xs ys)"
using Cons.hyps(2) by blast
define ys' where "ys' = take j ysa @ y # drop j ysa"
have xs': "xs' = take j xsa @ x # drop j xsa"
using ms_x j_len nth_j Cons.prems xsa_def
by (metis append_eq_append_conv append_take_drop_id diff_Suc_Suc Cons_nth_drop_Suc length_Cons
length_drop size_mset)
have j_len': "j \<le> length xsa"
using j_len xs' xsa_def
by (metis add_Suc_right append_take_drop_id length_Cons length_append less_eq_Suc_le not_less)
have "length ys' = length xs'"
unfolding ys'_def using Cons.prems len_a ms_x
by (metis add_Suc_right append_take_drop_id length_Cons length_append mset_eq_length)
moreover have "mset (zip xs' ys') = mset (zip (x # xs) (y # ys))"
unfolding xs' ys'_def
by (rule trans[OF mset_zip_take_Cons_drop_twice])
(auto simp: len_a ms_a j_len')
ultimately show ?case
by blast
qed
lemma list_all2_reorder_left_invariance:
assumes rel: "list_all2 R xs ys" and ms_x: "mset xs' = mset xs"
shows "\<exists>ys'. list_all2 R xs' ys' \<and> mset ys' = mset ys"
proof -
have len: "length xs = length ys"
using rel list_all2_conv_all_nth by auto
obtain ys' where
len': "length xs' = length ys'" and ms_xy: "mset (zip xs' ys') = mset (zip xs ys)"
using len ms_x by (metis ex_mset_zip_left)
have "list_all2 R xs' ys'"
using assms(1) len' ms_xy unfolding list_all2_iff by (blast dest: mset_eq_setD)
moreover have "mset ys' = mset ys"
using len len' ms_xy map_snd_zip mset_map by metis
ultimately show ?thesis
by blast
qed
inductive pred_mset :: "('a \<Rightarrow> bool) \<Rightarrow> 'a multiset \<Rightarrow> bool"
where
"pred_mset P {#}"
| "\<lbrakk>P a; pred_mset P M\<rbrakk> \<Longrightarrow> pred_mset P (add_mset a M)"
lemma pred_mset_iff: \<comment> \<open>TODO: alias for \<^const>\<open>Multiset.Ball\<close>\<close>
\<open>pred_mset P M \<longleftrightarrow> Multiset.Ball M P\<close> (is \<open>?P \<longleftrightarrow> ?Q\<close>)
proof
assume ?P
then show ?Q by induction simp_all
next
assume ?Q
then show ?P
by (induction M) (auto intro: pred_mset.intros)
qed
bnf "'a multiset"
map: image_mset
sets: set_mset
bd: natLeq
wits: "{#}"
rel: rel_mset
pred: pred_mset
proof -
show "image_mset (g \<circ> f) = image_mset g \<circ> image_mset f" for f g
unfolding comp_def by (rule ext) (simp add: comp_def image_mset.compositionality)
show "(\<And>z. z \<in> set_mset X \<Longrightarrow> f z = g z) \<Longrightarrow> image_mset f X = image_mset g X" for f g X
by (induct X) simp_all
show "card_order natLeq"
by (rule natLeq_card_order)
show "BNF_Cardinal_Arithmetic.cinfinite natLeq"
by (rule natLeq_cinfinite)
show "regularCard natLeq"
by (rule regularCard_natLeq)
show "ordLess2 (card_of (set_mset X)) natLeq" for X
by transfer
(auto simp: finite_iff_ordLess_natLeq[symmetric])
show "rel_mset R OO rel_mset S \<le> rel_mset (R OO S)" for R S
unfolding rel_mset_def[abs_def] OO_def
by (smt (verit, ccfv_SIG) list_all2_reorder_left_invariance list_all2_trans predicate2I)
show "rel_mset R =
(\<lambda>x y. \<exists>z. set_mset z \<subseteq> {(x, y). R x y} \<and>
image_mset fst z = x \<and> image_mset snd z = y)" for R
unfolding rel_mset_def[abs_def]
by (metis (no_types, lifting) ex_mset list.in_rel mem_Collect_eq mset_map set_mset_mset)
show "pred_mset P = (\<lambda>x. Ball (set_mset x) P)" for P
by (simp add: fun_eq_iff pred_mset_iff)
qed auto
inductive rel_mset' :: \<open>('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> 'a multiset \<Rightarrow> 'b multiset \<Rightarrow> bool\<close>
where
Zero[intro]: "rel_mset' R {#} {#}"
| Plus[intro]: "\<lbrakk>R a b; rel_mset' R M N\<rbrakk> \<Longrightarrow> rel_mset' R (add_mset a M) (add_mset b N)"
lemma rel_mset_Zero: "rel_mset R {#} {#}"
unfolding rel_mset_def Grp_def by auto
lemma rel_mset_Plus:
assumes ab: "R a b"
and MN: "rel_mset R M N"
shows "rel_mset R (add_mset a M) (add_mset b N)"
proof -
have "\<exists>ya. add_mset a (image_mset fst y) = image_mset fst ya \<and>
add_mset b (image_mset snd y) = image_mset snd ya \<and>
set_mset ya \<subseteq> {(x, y). R x y}"
if "R a b" and "set_mset y \<subseteq> {(x, y). R x y}" for y
using that by (intro exI[of _ "add_mset (a,b) y"]) auto
thus ?thesis
using assms
unfolding multiset.rel_compp_Grp Grp_def by blast
qed
lemma rel_mset'_imp_rel_mset: "rel_mset' R M N \<Longrightarrow> rel_mset R M N"
by (induct rule: rel_mset'.induct) (auto simp: rel_mset_Zero rel_mset_Plus)
lemma rel_mset_size: "rel_mset R M N \<Longrightarrow> size M = size N"
unfolding multiset.rel_compp_Grp Grp_def by auto
lemma rel_mset_Zero_iff [simp]:
shows "rel_mset rel {#} Y \<longleftrightarrow> Y = {#}" and "rel_mset rel X {#} \<longleftrightarrow> X = {#}"
by (auto simp add: rel_mset_Zero dest: rel_mset_size)
lemma multiset_induct2[case_names empty addL addR]:
assumes empty: "P {#} {#}"
and addL: "\<And>a M N. P M N \<Longrightarrow> P (add_mset a M) N"
and addR: "\<And>a M N. P M N \<Longrightarrow> P M (add_mset a N)"
shows "P M N"
by (induct N rule: multiset_induct; induct M rule: multiset_induct) (auto simp: assms)
lemma multiset_induct2_size[consumes 1, case_names empty add]:
assumes c: "size M = size N"
and empty: "P {#} {#}"
and add: "\<And>a b M N a b. P M N \<Longrightarrow> P (add_mset a M) (add_mset b N)"
shows "P M N"
using c
proof (induct M arbitrary: N rule: measure_induct_rule[of size])
case (less M)
show ?case
proof(cases "M = {#}")
case True hence "N = {#}" using less.prems by auto
thus ?thesis using True empty by auto
next
case False then obtain M1 a where M: "M = add_mset a M1" by (metis multi_nonempty_split)
have "N \<noteq> {#}" using False less.prems by auto
then obtain N1 b where N: "N = add_mset b N1" by (metis multi_nonempty_split)
have "size M1 = size N1" using less.prems unfolding M N by auto
thus ?thesis using M N less.hyps add by auto
qed
qed
lemma msed_map_invL:
assumes "image_mset f (add_mset a M) = N"
shows "\<exists>N1. N = add_mset (f a) N1 \<and> image_mset f M = N1"
proof -
have "f a \<in># N"
using assms multiset.set_map[of f "add_mset a M"] by auto
then obtain N1 where N: "N = add_mset (f a) N1" using multi_member_split by metis
have "image_mset f M = N1" using assms unfolding N by simp
thus ?thesis using N by blast
qed
lemma msed_map_invR:
assumes "image_mset f M = add_mset b N"
shows "\<exists>M1 a. M = add_mset a M1 \<and> f a = b \<and> image_mset f M1 = N"
proof -
obtain a where a: "a \<in># M" and fa: "f a = b"
using multiset.set_map[of f M] unfolding assms
by (metis image_iff union_single_eq_member)
then obtain M1 where M: "M = add_mset a M1" using multi_member_split by metis
have "image_mset f M1 = N" using assms unfolding M fa[symmetric] by simp
thus ?thesis using M fa by blast
qed
lemma msed_rel_invL:
assumes "rel_mset R (add_mset a M) N"
shows "\<exists>N1 b. N = add_mset b N1 \<and> R a b \<and> rel_mset R M N1"
proof -
obtain K where KM: "image_mset fst K = add_mset a M"
and KN: "image_mset snd K = N" and sK: "set_mset K \<subseteq> {(a, b). R a b}"
using assms
unfolding multiset.rel_compp_Grp Grp_def by auto
obtain K1 ab where K: "K = add_mset ab K1" and a: "fst ab = a"
and K1M: "image_mset fst K1 = M" using msed_map_invR[OF KM] by auto
obtain N1 where N: "N = add_mset (snd ab) N1" and K1N1: "image_mset snd K1 = N1"
using msed_map_invL[OF KN[unfolded K]] by auto
have Rab: "R a (snd ab)" using sK a unfolding K by auto
have "rel_mset R M N1" using sK K1M K1N1
unfolding K multiset.rel_compp_Grp Grp_def by auto
thus ?thesis using N Rab by auto
qed
lemma msed_rel_invR:
assumes "rel_mset R M (add_mset b N)"
shows "\<exists>M1 a. M = add_mset a M1 \<and> R a b \<and> rel_mset R M1 N"
proof -
obtain K where KN: "image_mset snd K = add_mset b N"
and KM: "image_mset fst K = M" and sK: "set_mset K \<subseteq> {(a, b). R a b}"
using assms
unfolding multiset.rel_compp_Grp Grp_def by auto
obtain K1 ab where K: "K = add_mset ab K1" and b: "snd ab = b"
and K1N: "image_mset snd K1 = N" using msed_map_invR[OF KN] by auto
obtain M1 where M: "M = add_mset (fst ab) M1" and K1M1: "image_mset fst K1 = M1"
using msed_map_invL[OF KM[unfolded K]] by auto
have Rab: "R (fst ab) b" using sK b unfolding K by auto
have "rel_mset R M1 N" using sK K1N K1M1
unfolding K multiset.rel_compp_Grp Grp_def by auto
thus ?thesis using M Rab by auto
qed
lemma rel_mset_imp_rel_mset':
assumes "rel_mset R M N"
shows "rel_mset' R M N"
using assms proof(induct M arbitrary: N rule: measure_induct_rule[of size])
case (less M)
have c: "size M = size N" using rel_mset_size[OF less.prems] .
show ?case
proof(cases "M = {#}")
case True hence "N = {#}" using c by simp
thus ?thesis using True rel_mset'.Zero by auto
next
case False then obtain M1 a where M: "M = add_mset a M1" by (metis multi_nonempty_split)
obtain N1 b where N: "N = add_mset b N1" and R: "R a b" and ms: "rel_mset R M1 N1"
using msed_rel_invL[OF less.prems[unfolded M]] by auto
have "rel_mset' R M1 N1" using less.hyps[of M1 N1] ms unfolding M by simp
thus ?thesis using rel_mset'.Plus[of R a b, OF R] unfolding M N by simp
qed
qed
lemma rel_mset_rel_mset': "rel_mset R M N = rel_mset' R M N"
using rel_mset_imp_rel_mset' rel_mset'_imp_rel_mset by auto
text \<open>The main end product for \<^const>\<open>rel_mset\<close>: inductive characterization:\<close>
lemmas rel_mset_induct[case_names empty add, induct pred: rel_mset] =
rel_mset'.induct[unfolded rel_mset_rel_mset'[symmetric]]
subsection \<open>Size setup\<close>
lemma size_multiset_o_map: "size_multiset g \<circ> image_mset f = size_multiset (g \<circ> f)"
apply (rule ext)
subgoal for x by (induct x) auto
done
lemma size_mset_SucE: "size A = Suc n \<Longrightarrow> (\<And>a B. A = {#a#} + B \<Longrightarrow> size B = n \<Longrightarrow> P) \<Longrightarrow> P"
by (cases A) (auto simp add: ac_simps)
lemma size_Suc_Diff1: "x \<in># M \<Longrightarrow> Suc (size (M - {#x#})) = size M"
using arg_cong[OF insert_DiffM, of _ _ size] by simp
lemma size_Diff_singleton: "x \<in># M \<Longrightarrow> size (M - {#x#}) = size M - 1"
by (simp flip: size_Suc_Diff1)
lemma size_Diff_singleton_if: "size (A - {#x#}) = (if x \<in># A then size A - 1 else size A)"
by (simp add: diff_single_trivial size_Diff_singleton)
lemma size_Un_Int: "size A + size B = size (A \<union># B) + size (A \<inter># B)"
by (metis inter_subset_eq_union size_union subset_mset.diff_add union_diff_inter_eq_sup)
lemma size_Un_disjoint: "A \<inter># B = {#} \<Longrightarrow> size (A \<union># B) = size A + size B"
using size_Un_Int[of A B] by simp
lemma size_Diff_subset_Int: "size (M - M') = size M - size (M \<inter># M')"
by (metis diff_intersect_left_idem size_Diff_submset subset_mset.inf_le1)
lemma size_psubset: "M \<subseteq># M' \<Longrightarrow> size M < size M' \<Longrightarrow> M \<subset># M'"
using less_irrefl subset_mset_def by blast
subsection \<open>The set of multisets of a given size\<close>
(* contributed by Manuel Eberl *)
text \<open>
The following operator gives the set of all multisets consisting of $n$ elements drawn from
the set $A$. In other words: all the different ways to put $n$ unlabelled balls into
the labelled bins $A$.
\<close>
definition multisets_of_size :: "'a set \<Rightarrow> nat \<Rightarrow> 'a multiset set" where
"multisets_of_size A n = {X. set_mset X \<subseteq> A \<and> size X = n}"
lemma
assumes "X \<in> multisets_of_size A n"
shows multisets_of_size_subset: "set_mset X \<subseteq> A"
and multisets_of_size_size: "size X = n"
using assms by (auto simp: multisets_of_size_def)
lemma multisets_of_size_mono:
assumes "A \<subseteq> B"
shows "multisets_of_size A n \<subseteq> multisets_of_size B n"
unfolding multisets_of_size_def
by (intro Collect_mono) (use assms in auto)
lemma multisets_of_size_0 [simp]: "multisets_of_size A 0 = {{#}}"
proof (intro equalityI subsetI)
fix h :: "'a multiset" assume "h \<in> {{#}}"
thus "h \<in> multisets_of_size A 0"
by (auto simp: multisets_of_size_def)
qed (auto simp: multisets_of_size_def fun_eq_iff)
lemma multisets_of_size_empty [simp]: "n > 0 \<Longrightarrow> multisets_of_size {} n = {}"
by (auto simp: multisets_of_size_def fun_eq_iff)
lemma count_le_size: "count X x \<le> size X"
by (induction X) auto
lemma bij_betw_multisets_of_size_insert:
assumes "a \<notin> A"
shows "bij_betw (\<lambda>(m,X). X + replicate_mset m a)
(SIGMA m:{0..n}. multisets_of_size A (n - m)) (multisets_of_size (insert a A) n)"
proof -
define B where "B = (SIGMA m:{0..n}. multisets_of_size A (n - m))"
define C where "C = (multisets_of_size (insert a A) n)"
define f where "f = (\<lambda>(m,X). X + replicate_mset m a)"
define g where "g = (\<lambda>X. (count X a, filter_mset (\<lambda>x. x \<noteq> a) X))"
note defs = B_def C_def f_def g_def
have *: "size (filter_mset (\<lambda>x. x \<noteq> a) X) = size X - count X a" for X
proof -
have "size X = size (filter_mset (\<lambda>x. x \<noteq> a) X) + count X a"
by (induction X) auto
thus ?thesis
by linarith
qed
have 1: "f mX \<in> C" if "mX \<in> B" for mX
using that by (auto simp: multisets_of_size_def defs split: if_splits)
have 2: "g X \<in> B" if "X \<in> C" for X
using that by (auto simp: multisets_of_size_def count_le_size * defs)
have 3: "g (f mX) = mX" if "mX \<in> B" for mX
using that assms
by (auto simp: multisets_of_size_def multiset_eq_iff defs simp flip: not_in_iff)
have 4: "f (g X) = X" if "X \<in> C" for X
using that
by (auto simp: multisets_of_size_def multiset_eq_iff defs simp flip: not_in_iff)
have "f ` B = C"
using 124 unfolding set_eq_iff image_iff by metis
moreover have "inj_on f B"
using 3 unfolding inj_on_def by metis
ultimately show ?thesis
unfolding bij_betw_def defs by metis
qed
lemma multisets_of_size_insert:
assumes "a \<notin> A"
shows "multisets_of_size (insert a A) n =
(\<Union>m\<le>n. (\<lambda>X. X + replicate_mset m a) ` multisets_of_size A (n - m))"
proof -
have "multisets_of_size (insert a A) n =
(\<lambda>(m,X). X + replicate_mset m a) ` (SIGMA m:{0..n}. multisets_of_size A (n - m))"
using bij_betw_multisets_of_size_insert[OF assms, of n] unfolding bij_betw_def by simp
also have "\<dots> = (\<Union>m\<le>n. (\<lambda>X. X + replicate_mset m a) ` multisets_of_size A (n - m))"
unfolding Sigma_def image_UN atLeast0AtMost image_insert image_empty prod.case
UNION_singleton_eq_range image_image by (rule refl)
finally show ?thesis .
qed
primrec multisets_of_size_list :: "'a list \<Rightarrow> nat \<Rightarrow> 'a list list" where
"multisets_of_size_list [] n = (if n = 0 then [[]] else [])"
| "multisets_of_size_list (x # xs) n =
[replicate m x @ ys . m \<leftarrow> [0..<n+1], ys \<leftarrow> multisets_of_size_list xs (n - m)]"
lemma multisets_of_size_list_correct:
assumes "distinct xs"
shows "mset ` set (multisets_of_size_list xs n) = multisets_of_size (set xs) n"
using assms
proof (induction xs arbitrary: n)
case Nil
thus ?case
by (cases "n = 0") auto
next
case (Cons x xs n)
have IH: "multisets_of_size (set xs) n = mset ` set (multisets_of_size_list xs n)" for n
by (rule Cons.IH [symmetric]) (use Cons.prems in auto)
from Cons.prems have "x \<notin> set xs"
by auto
thus ?case
by (simp add: multisets_of_size_insert image_UN atLeastLessThanSuc_atLeastAtMost image_image
add_ac atLeast0AtMost IH del: upt_Suc)
qed
lemma multisets_of_size_code [code]:
"multisets_of_size (set xs) n = set (map mset (multisets_of_size_list (remdups xs) n))"
using multisets_of_size_list_correct[of "remdups xs"] by simp
lemma finite_multisets_of_size [intro]:
assumes "finite A"
shows "finite (multisets_of_size A n)"
using assms
proof (induction arbitrary: n rule: finite_induct)
case empty
thus ?case
by (cases "n = 0") auto
next
case (insert x A n)
have "finite (SIGMA m:{0..n}. multisets_of_size A (n - m))"
by (auto intro: insert.IH)
also have "?this \<longleftrightarrow> finite (multisets_of_size (insert x A) n)"
by (rule bij_betw_finite, rule bij_betw_multisets_of_size_insert) fact
finally show ?case .
qed
lemma card_multisets_of_size:
assumes "finite A"
shows "card (multisets_of_size A n) = (card A + n - 1) choose n"
using assms
proof (induction A arbitrary: n rule: finite_induct)
case empty
thus ?case
by (cases "n = 0") auto
next
case (insert a A n)
have "card (multisets_of_size (insert a A) n) = card (SIGMA m:{0..n}. multisets_of_size A (n - m))"
using bij_betw_same_card[OF bij_betw_multisets_of_size_insert[of a A], of n] insert.hyps
by simp
also have "\<dots> = (\<Sum>m=0..n. card (multisets_of_size A (n - m)))"
by (intro card_SigmaI) (use insert.hyps in auto)
also have "\<dots> = (\<Sum>m=0..n. (card A + (n - m) - 1) choose (n - m))"
by (intro sum.cong insert.IH refl)
also have "\<dots> = (\<Sum>m=0..n. (card A + m - 1) choose m)"
by (intro sum.reindex_bij_witness[of _ "\<lambda>m. n - m" "\<lambda>m. n - m"]) auto
also have "\<dots> = (card A + n) choose n"
proof (cases "card A = 0")
case True
have "(\<Sum>m=0..n. (card A + m - 1) choose m) = (\<Sum>m\<in>{0}. (m-1) choose m)"
by (intro sum.mono_neutral_cong_right) (use True in auto)
also have "\<dots> = 1"
by simp
also have "\<dots> = (card A + n) choose n"
using True by simp
finally show ?thesis .
next
case False
have "(\<Sum>m=0..n. (card A + m - 1) choose m) = (\<Sum>m\<le>n. ((card A - 1) + m) choose m)"
by (intro sum.cong) (use False in \<open>auto simp: algebra_simps\<close>)
also have "\<dots> = (\<Sum>m\<le>n. ((card A - 1) + m) choose (card A - 1))"
by (subst binomial_symmetric) auto
also have "\<dots> = (card A + n) choose n"
using choose_rising_sum(2)[of "card A - 1" n] False by simp
finally show ?thesis .
qed
finally show ?case
using insert.hyps by simp
qed
end
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.200 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.