Theory Nested_Multisets_Ordinals.Duplicate_Free_Multiset
theory Duplicate_Free_Multiset
imports Multiset_More
begin
section ‹Duplicate Free Multisets›
text ‹Duplicate free multisets are isomorphic to finite sets, but it can be useful to reason about
duplication to speak about intermediate execution steps in the refinements.
›
definition distinct_mset :: "'a multiset ⇒ bool" where
"distinct_mset S ⟷ (∀a. a ∈# S ⟶ count S a = 1)"
lemma distinct_mset_count_less_1: "distinct_mset S ⟷ (∀a. count S a ≤ 1)"
using eq_iff nat_le_linear unfolding distinct_mset_def by fastforce
lemma distinct_mset_empty[simp]: "distinct_mset {#}"
unfolding distinct_mset_def by auto
lemma distinct_mset_singleton: "distinct_mset {#a#}"
unfolding distinct_mset_def by auto
lemma distinct_mset_union:
assumes dist: "distinct_mset (A + B)"
shows "distinct_mset A"
unfolding distinct_mset_count_less_1
proof (rule allI)
fix a
have ‹count A a ≤ count (A + B) a› by auto
moreover have ‹count (A + B) a ≤ 1›
using dist unfolding distinct_mset_count_less_1 by auto
ultimately show ‹count A a ≤ 1›
by simp
qed
lemma distinct_mset_minus[simp]: "distinct_mset A ⟹ distinct_mset (A - B)"
by (metis diff_subset_eq_self mset_subset_eq_exists_conv distinct_mset_union)
lemma distinct_mset_rempdups_union_mset:
assumes "distinct_mset A" and "distinct_mset B"
shows "A ∪# B = remdups_mset (A + B)"
using assms nat_le_linear unfolding remdups_mset_def
by (force simp add: multiset_eq_iff max_def count_mset_set_if distinct_mset_def not_in_iff)
lemma distinct_mset_add_mset[simp]: "distinct_mset (add_mset a L) ⟷ a ∉# L ∧ distinct_mset L"
unfolding distinct_mset_def
apply (rule iffI)
apply (auto split: if_split_asm; fail)[]
by (auto simp: not_in_iff; fail)
lemma distinct_mset_size_eq_card: "distinct_mset C ⟹ size C = card (set_mset C)"
by (induction C) auto
lemma distinct_mset_add:
"distinct_mset (L + L') ⟷ distinct_mset L ∧ distinct_mset L' ∧ L ∩# L' = {#}"
by (induction L arbitrary: L') auto
lemma distinct_mset_set_mset_ident[simp]: "distinct_mset M ⟹ mset_set (set_mset M) = M"
by (induction M) auto
lemma distinct_finite_set_mset_subseteq_iff[iff]:
assumes "distinct_mset M" "finite N"
shows "set_mset M ⊆ N ⟷ M ⊆# mset_set N"
by (metis assms distinct_mset_set_mset_ident finite_set_mset msubset_mset_set_iff)
lemma distinct_mem_diff_mset:
assumes dist: "distinct_mset M" and mem: "x ∈ set_mset (M - N)"
shows "x ∉ set_mset N"
proof -
have "count M x = 1"
using dist mem by (meson distinct_mset_def in_diffD)
then show ?thesis
using mem by (metis count_greater_eq_one_iff in_diff_count not_less)
qed
lemma distinct_set_mset_eq:
assumes "distinct_mset M" "distinct_mset N" "set_mset M = set_mset N"
shows "M = N"
using assms distinct_mset_set_mset_ident by fastforce
lemma distinct_mset_union_mset[simp]:
‹distinct_mset (D ∪# C) ⟷ distinct_mset D ∧ distinct_mset C›
unfolding distinct_mset_count_less_1 by force
lemma distinct_mset_inter_mset:
"distinct_mset C ⟹ distinct_mset (C ∩# D)"
"distinct_mset D ⟹ distinct_mset (C ∩# D)"
by (auto simp add: distinct_mset_def min_def count_eq_zero_iff elim!: le_SucE)
lemma distinct_mset_remove1_All: "distinct_mset C ⟹ remove1_mset L C = removeAll_mset L C"
by (auto simp: multiset_eq_iff distinct_mset_count_less_1)
lemma distinct_mset_size_2: "distinct_mset {#a, b#} ⟷ a ≠ b"
by auto
lemma distinct_mset_filter: "distinct_mset M ⟹ distinct_mset {# L ∈# M. P L#}"
by (simp add: distinct_mset_def)
lemma distinct_mset_mset_distinct[simp]: ‹distinct_mset (mset xs) = distinct xs›
by (induction xs) auto
lemma distinct_image_mset_inj:
‹inj_on f (set_mset M) ⟹ distinct_mset (image_mset f M) ⟷ distinct_mset M›
by (induction M) (auto simp: inj_on_def)
lemma distinct_mset_remdups_mset_id: ‹distinct_mset C ⟹ remdups_mset C = C›
by (induction C) auto
lemma distinct_mset_image_mset:
‹distinct_mset (image_mset f (mset xs)) ⟷ distinct (map f xs)›
apply (subst mset_map[symmetric])
apply (subst distinct_mset_mset_distinct)
..
lemma distinct_mset_mono: ‹D' ⊆# D ⟹ distinct_mset D ⟹ distinct_mset D'›
by (metis distinct_mset_union subset_mset.le_iff_add)
lemma distinct_mset_mono_strict: ‹D' ⊂# D ⟹ distinct_mset D ⟹ distinct_mset D'›
using distinct_mset_mono by auto
lemma distinct_set_mset_eq_iff:
assumes ‹distinct_mset M› ‹distinct_mset N›
shows ‹set_mset M = set_mset N ⟷ M = N›
using assms distinct_mset_set_mset_ident by fastforce
lemma distinct_mset_union2:
‹distinct_mset (A + B) ⟹ distinct_mset B›
using distinct_mset_union[of B A]
by (auto simp: ac_simps)
lemma distinct_mset_mset_set: ‹distinct_mset (mset_set A)›
unfolding distinct_mset_def count_mset_set_if by (auto simp: not_in_iff)
lemma distinct_mset_inter_remdups_mset:
assumes dist: ‹distinct_mset A›
shows ‹A ∩# remdups_mset B = A ∩# B›
proof -
have [simp]: ‹A' ∩# remove1_mset a (remdups_mset Aa) = A' ∩# Aa›
if
‹A' ∩# remdups_mset Aa = A' ∩# Aa› and
‹a ∉# A'› and
‹a ∈# Aa›
for A' Aa :: ‹'a multiset› and a
by (metis insert_DiffM inter_add_right1 set_mset_remdups_mset that)
show ?thesis
using dist
apply (induction A)
subgoal by auto
subgoal for a A'
by (cases ‹a ∈# B›)
(use multi_member_split[of a ‹B›] multi_member_split[of a ‹A›] in
‹auto simp: mset_set.insert_remove›)
done
qed
abbreviation (input) is_mset_set :: ‹'a multiset ⇒ bool›
where ‹is_mset_set ≡ distinct_mset›
lemma is_mset_set_def:
‹is_mset_set X ⟷ (∀x ∈# X. count X x = 1)›
by (auto simp add: distinct_mset_def)
lemma is_mset_setD[dest]: "is_mset_set X ⟹ x ∈# X ⟹ count X x = 1"
unfolding is_mset_set_def by auto
lemma is_mset_setI[intro]:
assumes "⋀x. x ∈# X ⟹ count X x = 1"
shows "is_mset_set X"
using assms unfolding is_mset_set_def by auto
lemma is_mset_set[simp]: "is_mset_set (mset_set X)"
by (fact distinct_mset_mset_set)
lemma is_mset_set_add[simp]:
"is_mset_set (X + {#x#}) ⟷ is_mset_set X ∧ x ∉# X" (is "?L ⟷ ?R")
proof(intro iffI conjI)
assume L: ?L
with count_eq_zero_iff count_single show "is_mset_set X"
unfolding is_mset_set_def
by (metis (no_types, opaque_lifting) add_mset_add_single count_add_mset nat.inject set_mset_add_mset_insert union_single_eq_member)
show "x ∉# X"
proof
assume "x ∈# X"
then have "count (X + {#x#}) x > 1" by auto
with L show False by (auto simp: is_mset_set_def)
qed
next
assume R: ?R show ?L
proof
fix x' assume x': "x' ∈# X + {#x#}"
show "count (X + {#x#}) x' = 1"
proof(cases "x' ∈# X")
case True with R have "count X x' = 1" by auto
moreover from True R have "count {#x#} x' = 0" by auto
ultimately show ?thesis by auto
next
case False then have "count X x' = 0" by (simp add: not_in_iff)
with R x' show ?thesis by auto
qed
qed
qed
lemma mset_set_id:
assumes "is_mset_set X"
shows "mset_set (set_mset X) = X"
using assms by (fact distinct_mset_set_mset_ident)
lemma is_mset_set_image:
assumes "inj_on f (set_mset X)" and "is_mset_set X"
shows "is_mset_set (image_mset f X)"
proof (cases X)
case empty then show ?thesis by auto
next
case (add x X)
define X' where "X' ≡ add_mset x X"
with assms add have inj:"inj_on f (set_mset X')"
and X': "is_mset_set X'" by auto
show ?thesis
proof(unfold add, intro is_mset_setI, fold X'_def)
fix y assume "y ∈# image_mset f X'"
then have "y ∈ f ` set_mset X'" by auto
with inj have "∃!x'. x' ∈# X' ∧ y = f x'" by (meson imageE inj_onD)
then obtain x' where x': "{x'. x' ∈# X' ∧ y = f x'} = {x'}" by auto
then have "count (image_mset f X') y = count X' x'"
by (simp add: count_image_mset')
also from X' x' have "... = 1" by auto
finally show "count (image_mset f X') y = 1".
qed
qed
end