(* Title: HOL/Library/Multiset.thy
Author: Tobias Nipkow, Markus Wenzel, Lawrence C Paulson, Norbert Voelker
Author: Andrei Popescu, TU Muenchen
Author: Jasmin Blanchette, Inria, LORIA, MPII
Author: Dmitriy Traytel, TU Muenchen
Author: Mathias Fleury, MPII
*)
section \<open>(Finite) multisets\<close>
theory Multiset
imports Main
begin
subsection \<open>The type of multisets\<close>
definition "multiset = {f :: 'a \<Rightarrow> nat. finite {x. f x > 0}}"
typedef 'a multiset = "multiset :: ('a \<Rightarrow> nat) set"
morphisms count Abs_multiset
unfolding multiset_def
proof
show "(\<lambda>x. 0::nat) \<in> {f. finite {x. f x > 0}}" by simp
qed
setup_lifting type_definition_multiset
lemma multiset_eq_iff: "M = N \<longleftrightarrow> (\<forall>a. count M a = count N a)"
by (simp only: count_inject [symmetric] fun_eq_iff)
lemma multiset_eqI: "(\<And>x. count A x = count B x) \<Longrightarrow> A = B"
using multiset_eq_iff by auto
text \<open>Preservation of the representing set @{term multiset}.\<close>
lemma const0_in_multiset: "(\<lambda>a. 0) \<in> multiset"
by (simp add: multiset_def)
lemma only1_in_multiset: "(\<lambda>b. if b = a then n else 0) \<in> multiset"
by (simp add: multiset_def)
lemma union_preserves_multiset: "M \<in> multiset \<Longrightarrow> N \<in> multiset \<Longrightarrow> (\<lambda>a. M a + N a) \<in> multiset"
by (simp add: multiset_def)
lemma diff_preserves_multiset:
assumes "M \<in> multiset"
shows "(\<lambda>a. M a - N a) \<in> multiset"
proof -
have "{x. N x < M x} \<subseteq> {x. 0 < M x}"
by auto
with assms show ?thesis
by (auto simp add: multiset_def intro: finite_subset)
qed
lemma filter_preserves_multiset:
assumes "M \<in> multiset"
shows "(\<lambda>x. if P x then M x else 0) \<in> multiset"
proof -
have "{x. (P x \<longrightarrow> 0 < M x) \<and> P x} \<subseteq> {x. 0 < M x}"
by auto
with assms show ?thesis
by (auto simp add: multiset_def intro: finite_subset)
qed
lemmas in_multiset = const0_in_multiset only1_in_multiset
union_preserves_multiset diff_preserves_multiset filter_preserves_multiset
subsection \<open>Representing multisets\<close>
text \<open>Multiset enumeration\<close>
instantiation multiset :: (type) cancel_comm_monoid_add
begin
lift_definition zero_multiset :: "'a multiset" is "\<lambda>a. 0"
by (rule const0_in_multiset)
abbreviation Mempty :: "'a multiset" ("{#}") where
"Mempty \<equiv> 0"
lift_definition plus_multiset :: "'a multiset \<Rightarrow> 'a multiset \<Rightarrow> 'a multiset" is "\<lambda>M N. (\<lambda>a. M a + N a)"
by (rule union_preserves_multiset)
lift_definition minus_multiset :: "'a multiset \<Rightarrow> 'a multiset \<Rightarrow> 'a multiset" is "\<lambda> M N. \<lambda>a. M a - N a"
by (rule diff_preserves_multiset)
instance
by (standard; transfer; simp add: fun_eq_iff)
end
context
begin
qualified definition is_empty :: "'a multiset \<Rightarrow> bool" where
[code_abbrev]: "is_empty A \<longleftrightarrow> A = {#}"
end
lift_definition single :: "'a \<Rightarrow> 'a multiset" is "\<lambda>a b. if b = a then 1 else 0"
by (rule only1_in_multiset)
syntax
"_multiset" :: "args \<Rightarrow> 'a multiset" ("{#(_)#}")
translations
"{#x, xs#}" == "{#x#} + {#xs#}"
"{#x#}" == "CONST single x"
lemma count_empty [simp]: "count {#} a = 0"
by (simp add: zero_multiset.rep_eq)
lemma count_single [simp]: "count {#b#} a = (if b = a then 1 else 0)"
by (simp add: single.rep_eq)
subsection \<open>Basic operations\<close>
subsubsection \<open>Conversion to set and membership\<close>
definition set_mset :: "'a multiset \<Rightarrow> 'a set"
where "set_mset M = {x. count M x > 0}"
abbreviation Melem :: "'a \<Rightarrow> 'a multiset \<Rightarrow> bool"
where "Melem a M \<equiv> a \<in> set_mset M"
notation
Melem ("op \<in>#") and
Melem ("(_/ \<in># _)" [51, 51] 50)
notation (ASCII)
Melem ("op :#") and
Melem ("(_/ :# _)" [51, 51] 50)
abbreviation not_Melem :: "'a \<Rightarrow> 'a multiset \<Rightarrow> bool"
where "not_Melem a M \<equiv> a \<notin> set_mset M"
notation
not_Melem ("op \<notin>#") and
not_Melem ("(_/ \<notin># _)" [51, 51] 50)
notation (ASCII)
not_Melem ("op ~:#") and
not_Melem ("(_/ ~:# _)" [51, 51] 50)
context
begin
qualified abbreviation Ball :: "'a multiset \<Rightarrow> ('a \<Rightarrow> bool) \<Rightarrow> bool"
where "Ball M \<equiv> Set.Ball (set_mset M)"