default implementation of multisets by list with reasonable coverage of operations on multisets
authorhaftmann
Wed, 03 Apr 2013 22:26:04 +0200
changeset 51600 197e25f13f0c
parent 51599 1559e9266280
child 51609 0f26c787a7a4
default implementation of multisets by list with reasonable coverage of operations on multisets
src/HOL/Big_Operators.thy
src/HOL/Library/DAList_Multiset.thy
src/HOL/Library/Multiset.thy
--- a/src/HOL/Big_Operators.thy	Wed Apr 03 22:26:04 2013 +0200
+++ b/src/HOL/Big_Operators.thy	Wed Apr 03 22:26:04 2013 +0200
@@ -968,6 +968,15 @@
   thus "setsum f (A - insert x F) = setsum f A - setsum f (insert x F)" by simp
 qed
 
+lemma setsum_comp_morphism:
+  assumes "h 0 = 0" and "\<And>x y. h (x + y) = h x + h y"
+  shows "setsum (h \<circ> g) A = h (setsum g A)"
+proof (cases "finite A")
+  case False then show ?thesis by (simp add: assms)
+next
+  case True then show ?thesis by (induct A) (simp_all add: assms)
+qed
+
 
 subsubsection {* Cardinality as special case of @{const setsum} *}
 
--- a/src/HOL/Library/DAList_Multiset.thy	Wed Apr 03 22:26:04 2013 +0200
+++ b/src/HOL/Library/DAList_Multiset.thy	Wed Apr 03 22:26:04 2013 +0200
@@ -8,6 +8,53 @@
 imports Multiset DAList
 begin
 
+text {* Delete prexisting code equations *}
+
+lemma [code, code del]:
+  "plus = (plus :: 'a multiset \<Rightarrow> _)"
+  ..
+
+lemma [code, code del]:
+  "minus = (minus :: 'a multiset \<Rightarrow> _)"
+  ..
+
+lemma [code, code del]:
+  "inf = (inf :: 'a multiset \<Rightarrow> _)"
+  ..
+
+lemma [code, code del]:
+  "image_mset = image_mset"
+  ..
+
+lemma [code, code del]:
+  "Multiset.filter = Multiset.filter"
+  ..
+
+lemma [code, code del]:
+  "count = count"
+  ..
+
+lemma [code, code del]:
+  "mcard = mcard"
+  ..
+
+lemma [code, code del]:
+  "msetsum = msetsum"
+  ..
+
+lemma [code, code del]:
+  "msetprod = msetprod"
+  ..
+
+lemma [code, code del]:
+  "set_of = set_of"
+  ..
+
+lemma [code, code del]:
+  "sorted_list_of_multiset = sorted_list_of_multiset"
+  ..
+
+
 text {* Raw operations on lists *}
 
 definition join_raw :: "('key \<Rightarrow> 'val \<times> 'val \<Rightarrow> 'val) \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list \<Rightarrow> ('key \<times> 'val) list"
@@ -174,62 +221,23 @@
   qed
 qed
 
-instantiation multiset :: (equal) equal
+declare multiset_inter_def [code]
+
+lemma [code]:
+  "multiset_of [] = {#}"
+  "multiset_of (x # xs) = multiset_of xs + {#x#}"
+  by simp_all
+
+instantiation multiset :: (exhaustive) exhaustive
 begin
 
-definition
-  [code]: "HOL.equal A B \<longleftrightarrow> (A::'a multiset) \<le> B \<and> B \<le> A"
-
-instance
-  by default (simp add: equal_multiset_def eq_iff)
-
-end
-
-text {* Quickcheck generators *}
-
-definition (in term_syntax)
-  bagify :: "('a\<Colon>typerep, nat) alist \<times> (unit \<Rightarrow> Code_Evaluation.term)
-    \<Rightarrow> 'a multiset \<times> (unit \<Rightarrow> Code_Evaluation.term)" where
-  [code_unfold]: "bagify xs = Code_Evaluation.valtermify Bag {\<cdot>} xs"
-
-notation fcomp (infixl "\<circ>>" 60)
-notation scomp (infixl "\<circ>\<rightarrow>" 60)
-
-instantiation multiset :: (random) random
-begin
-
-definition
-  "Quickcheck_Random.random i = Quickcheck_Random.random i \<circ>\<rightarrow> (\<lambda>xs. Pair (bagify xs))"
+definition exhaustive_multiset :: "('a multiset \<Rightarrow> (bool \<times> term list) option) \<Rightarrow> natural \<Rightarrow> (bool * term list) option"
+where
+  "exhaustive_multiset f i = Quickcheck_Exhaustive.exhaustive (\<lambda>xs. f (Bag xs)) i"
 
 instance ..
 
 end
 
-no_notation fcomp (infixl "\<circ>>" 60)
-no_notation scomp (infixl "\<circ>\<rightarrow>" 60)
-
-instantiation multiset :: (exhaustive) exhaustive
-begin
-
-definition exhaustive_multiset :: "('a multiset => (bool * term list) option) => natural => (bool * term list) option"
-where
-  "exhaustive_multiset f i = Quickcheck_Exhaustive.exhaustive (%xs. f (Bag xs)) i"
-
-instance ..
-
 end
 
-instantiation multiset :: (full_exhaustive) full_exhaustive
-begin
-
-definition full_exhaustive_multiset :: "('a multiset * (unit => term) => (bool * term list) option) => natural => (bool * term list) option"
-where
-  "full_exhaustive_multiset f i = Quickcheck_Exhaustive.full_exhaustive (%xs. f (bagify xs)) i"
-
-instance ..
-
-end
-
-hide_const (open) bagify
-
-end
--- a/src/HOL/Library/Multiset.thy	Wed Apr 03 22:26:04 2013 +0200
+++ b/src/HOL/Library/Multiset.thy	Wed Apr 03 22:26:04 2013 +0200
@@ -257,6 +257,10 @@
     (M = N \<and> a = b \<or> (\<exists>K. M = K + {#b#} \<and> N = K + {#a#}))"
   by (auto simp add: add_eq_conv_diff)
 
+lemma multi_member_split:
+  "x \<in># M \<Longrightarrow> \<exists>A. M = A + {#x#}"
+  by (rule_tac x = "M - {#x#}" in exI, simp)
+
 
 subsubsection {* Pointwise ordering induced by count *}
 
@@ -409,6 +413,30 @@
     by auto
 qed
 
+lemma empty_inter [simp]:
+  "{#} #\<inter> M = {#}"
+  by (simp add: multiset_eq_iff)
+
+lemma inter_empty [simp]:
+  "M #\<inter> {#} = {#}"
+  by (simp add: multiset_eq_iff)
+
+lemma inter_add_left1:
+  "\<not> x \<in># N \<Longrightarrow> (M + {#x#}) #\<inter> N = M #\<inter> N"
+  by (simp add: multiset_eq_iff)
+
+lemma inter_add_left2:
+  "x \<in># N \<Longrightarrow> (M + {#x#}) #\<inter> N = (M #\<inter> (N - {#x#})) + {#x#}"
+  by (simp add: multiset_eq_iff)
+
+lemma inter_add_right1:
+  "\<not> x \<in># N \<Longrightarrow> N #\<inter> (M + {#x#}) = N #\<inter> M"
+  by (simp add: multiset_eq_iff)
+
+lemma inter_add_right2:
+  "x \<in># N \<Longrightarrow> N #\<inter> (M + {#x#}) = ((N - {#x#}) #\<inter> M) + {#x#}"
+  by (simp add: multiset_eq_iff)
+
 
 subsubsection {* Filter (with comprehension syntax) *}
 
@@ -563,9 +591,6 @@
 shows "P"
 using assms by (induct M) simp_all
 
-lemma multi_member_split: "x \<in># M \<Longrightarrow> \<exists>A. M = A + {#x#}"
-by (rule_tac x="M - {#x#}" in exI, simp)
-
 lemma multi_drop_mem_not_eq: "c \<in># B \<Longrightarrow> B - {#c#} \<noteq> B"
 by (cases "B = {#}") (auto dest: multi_member_split)
 
@@ -952,6 +977,14 @@
   "multiset_of (insort x xs) = multiset_of xs + {#x#}"
   by (induct xs) (simp_all add: ac_simps)
 
+lemma in_multiset_of:
+  "x \<in># multiset_of xs \<longleftrightarrow> x \<in> set xs"
+  by (induct xs) simp_all
+
+lemma multiset_of_map:
+  "multiset_of (map f xs) = image_mset f (multiset_of xs)"
+  by (induct xs) simp_all
+
 definition multiset_of_set :: "'a set \<Rightarrow> 'a multiset"
 where
   "multiset_of_set = folding.F (\<lambda>x M. {#x#} + M) {#}"
@@ -965,6 +998,24 @@
   from multiset_of_set_def show "folding.F (\<lambda>x M. {#x#} + M) {#} = multiset_of_set" ..
 qed
 
+lemma count_multiset_of_set [simp]:
+  "finite A \<Longrightarrow> x \<in> A \<Longrightarrow> count (multiset_of_set A) x = 1" (is "PROP ?P")
+  "\<not> finite A \<Longrightarrow> count (multiset_of_set A) x = 0" (is "PROP ?Q")
+  "x \<notin> A \<Longrightarrow> count (multiset_of_set A) x = 0" (is "PROP ?R")
+proof -
+  { fix A
+    assume "x \<notin> A"
+    have "count (multiset_of_set A) x = 0"
+    proof (cases "finite A")
+      case False then show ?thesis by simp
+    next
+      case True from True `x \<notin> A` show ?thesis by (induct A) auto
+    qed
+  } note * = this
+  then show "PROP ?P" "PROP ?Q" "PROP ?R"
+  by (auto elim!: Set.set_insert)
+qed -- {* TODO: maybe define @{const multiset_of_set} also in terms of @{const Abs_multiset} *}
+
 context linorder
 begin
 
@@ -1194,6 +1245,14 @@
       (simp_all del: mem_set_of_iff add: setsum.distrib setsum.delta' insert_absorb, simp)
 qed
 
+lemma size_eq_mcard:
+  "size = mcard"
+  by (simp add: fun_eq_iff size_def mcard_unfold_setsum)
+
+lemma mcard_multiset_of:
+  "mcard (multiset_of xs) = length xs"
+  by (induct xs) simp_all
+
 
 subsection {* Alternative representations *}
 
@@ -1886,5 +1945,155 @@
 
 hide_const (open) fold
 
+
+subsection {* Naive implementation using lists *}
+
+code_datatype multiset_of
+
+lemma [code]:
+  "{#} = multiset_of []"
+  by simp
+
+lemma [code]:
+  "{#x#} = multiset_of [x]"
+  by simp
+
+lemma union_code [code]:
+  "multiset_of xs + multiset_of ys = multiset_of (xs @ ys)"
+  by simp
+
+lemma [code]:
+  "image_mset f (multiset_of xs) = multiset_of (map f xs)"
+  by (simp add: multiset_of_map)
+
+lemma [code]:
+  "Multiset.filter f (multiset_of xs) = multiset_of (filter f xs)"
+  by (simp add: multiset_of_filter)
+
+lemma [code]:
+  "multiset_of xs - multiset_of ys = multiset_of (fold remove1 ys xs)"
+  by (rule sym, induct ys arbitrary: xs) (simp_all add: diff_add diff_right_commute)
+
+lemma [code]:
+  "multiset_of xs #\<inter> multiset_of ys =
+    multiset_of (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. multiset_of (snd (fold (\<lambda>x (ys, zs).
+    if x \<in> set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, zs))) =
+      (multiset_of xs #\<inter> multiset_of ys) + multiset_of zs"
+  by (induct xs arbitrary: ys)
+    (auto simp add: mem_set_multiset_eq inter_add_right1 inter_add_right2 ac_simps)
+  then show ?thesis by simp
+qed
+
+lemma [code_unfold]:
+  "x \<in># multiset_of xs \<longleftrightarrow> x \<in> set xs"
+  by (simp add: in_multiset_of)
+
+lemma [code]:
+  "count (multiset_of 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 (multiset_of xs) x + n"
+    by (induct xs) simp_all
+  then show ?thesis by simp
+qed
+
+lemma [code]:
+  "set_of (multiset_of xs) = set xs"
+  by simp
+
+lemma [code]:
+  "sorted_list_of_multiset (multiset_of xs) = sort xs"
+  by (induct xs) simp_all
+
+lemma [code]: -- {* not very efficient, but representation-ignorant! *}
+  "multiset_of_set A = multiset_of (sorted_list_of_set A)"
+  apply (cases "finite A")
+  apply simp_all
+  apply (induct A rule: finite_induct)
+  apply (simp_all add: union_commute)
+  done
+
+lemma [code]:
+  "mcard (multiset_of xs) = length xs"
+  by (simp add: mcard_multiset_of)
+
+lemma [code]:
+  "A \<le> B \<longleftrightarrow> A #\<inter> B = A" 
+  by (auto simp add: inf.order_iff)
+
+instantiation multiset :: (equal) equal
+begin
+
+definition
+  [code]: "HOL.equal A B \<longleftrightarrow> (A::'a multiset) \<le> B \<and> B \<le> A"
+
+instance
+  by default (simp add: equal_multiset_def eq_iff)
+
 end
 
+lemma [code]:
+  "(A::'a multiset) < B \<longleftrightarrow> A \<le> B \<and> A \<noteq> B"
+  by auto
+
+lemma [code]:
+  "msetsum (multiset_of xs) = listsum xs"
+  by (induct xs) (simp_all add: add.commute)
+
+lemma [code]:
+  "msetprod (multiset_of xs) = fold times xs 1"
+proof -
+  have "\<And>x. fold times xs x = msetprod (multiset_of xs) * x"
+    by (induct xs) (simp_all add: mult.assoc)
+  then show ?thesis by simp
+qed
+
+lemma [code]:
+  "size = mcard"
+  by (fact size_eq_mcard)
+
+text {*
+  Exercise for the casual reader: add implementations for @{const le_multiset}
+  and @{const less_multiset} (multiset order).
+*}
+
+text {* Quickcheck generators *}
+
+definition (in term_syntax)
+  msetify :: "'a\<Colon>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 multiset_of {\<cdot>} xs"
+
+notation fcomp (infixl "\<circ>>" 60)
+notation scomp (infixl "\<circ>\<rightarrow>" 60)
+
+instantiation multiset :: (random) random
+begin
+
+definition
+  "Quickcheck_Random.random i = Quickcheck_Random.random i \<circ>\<rightarrow> (\<lambda>xs. Pair (msetify xs))"
+
+instance ..
+
+end
+
+no_notation fcomp (infixl "\<circ>>" 60)
+no_notation scomp (infixl "\<circ>\<rightarrow>" 60)
+
+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
+
+end
+