Theory Signed_Multiset
section ‹Signed (Finite) Multisets›
theory Signed_Multiset
imports Multiset_More
abbrevs
"!z" = "⇩z"
begin
unbundle multiset.lifting
subsection ‹Definition of Signed Multisets›
definition equiv_zmset :: "'a multiset × 'a multiset ⇒ 'a multiset × 'a multiset ⇒ bool" where
"equiv_zmset = (λ(Mp, Mn) (Np, Nn). Mp + Nn = Np + Mn)"
quotient_type 'a zmultiset = "'a multiset × 'a multiset" / equiv_zmset
by (rule equivpI, simp_all add: equiv_zmset_def reflp_def symp_def transp_def)
(metis multi_union_self_other_eq union_lcomm)
subsection ‹Basic Operations on Signed Multisets›
instantiation zmultiset :: (type) cancel_comm_monoid_add
begin
lift_definition zero_zmultiset :: "'a zmultiset" is "({#}, {#})" .
abbreviation empty_zmset :: "'a zmultiset" ("{#}⇩z") where
"empty_zmset ≡ 0"
lift_definition minus_zmultiset :: "'a zmultiset ⇒ 'a zmultiset ⇒ 'a zmultiset" is
"λ(Mp, Mn) (Np, Nn). (Mp + Nn, Mn + Np)"
by (auto simp: equiv_zmset_def union_commute union_lcomm)
lift_definition plus_zmultiset :: "'a zmultiset ⇒ 'a zmultiset ⇒ 'a zmultiset" is
"λ(Mp, Mn) (Np, Nn). (Mp + Np, Mn + Nn)"
by (auto simp: equiv_zmset_def union_commute union_lcomm)
instance
by (intro_classes; transfer) (auto simp: equiv_zmset_def)
end
instantiation zmultiset :: (type) group_add
begin
lift_definition uminus_zmultiset :: "'a zmultiset ⇒ 'a zmultiset" is "λ(Mp, Mn). (Mn, Mp)"
by (auto simp: equiv_zmset_def add.commute)
instance
by (intro_classes; transfer) (auto simp: equiv_zmset_def)
end
lift_definition zcount :: "'a zmultiset ⇒ 'a ⇒ int" is
"λ(Mp, Mn) x. int (count Mp x) - int (count Mn x)"
by (auto simp del: of_nat_add simp: equiv_zmset_def fun_eq_iff multiset_eq_iff diff_eq_eq
diff_add_eq eq_diff_eq of_nat_add[symmetric])
lemma zcount_inject: "zcount M = zcount N ⟷ M = N"
by transfer (auto simp del: of_nat_add simp: equiv_zmset_def fun_eq_iff multiset_eq_iff
diff_eq_eq diff_add_eq eq_diff_eq of_nat_add[symmetric])
lemma zmultiset_eq_iff: "M = N ⟷ (∀a. zcount M a = zcount N a)"
by (simp only: zcount_inject[symmetric] fun_eq_iff)
lemma zmultiset_eqI: "(⋀x. zcount A x = zcount B x) ⟹ A = B"
using zmultiset_eq_iff by auto
lemma zcount_uminus[simp]: "zcount (- A) x = - zcount A x"
by transfer auto
lift_definition add_zmset :: "'a ⇒ 'a zmultiset ⇒ 'a zmultiset" is
"λx (Mp, Mn). (add_mset x Mp, Mn)"
by (auto simp: equiv_zmset_def)
syntax
"_zmultiset" :: "args ⇒ 'a zmultiset" ("{#(_)#}⇩z")
translations
"{#x, xs#}⇩z" == "CONST add_zmset x {#xs#}⇩z"
"{#x#}⇩z" == "CONST add_zmset x {#}⇩z"
lemma zcount_empty[simp]: "zcount {#}⇩z a = 0"
by transfer auto
lemma zcount_add_zmset[simp]:
"zcount (add_zmset b A) a = (if b = a then zcount A a + 1 else zcount A a)"
by transfer auto
lemma zcount_single: "zcount {#b#}⇩z a = (if b = a then 1 else 0)"
by simp
lemma add_add_same_iff_zmset[simp]: "add_zmset a A = add_zmset a B ⟷ A = B"
by (auto simp: zmultiset_eq_iff)
lemma add_zmset_commute: "add_zmset x (add_zmset y M) = add_zmset y (add_zmset x M)"
by (auto simp: zmultiset_eq_iff)
lemma
singleton_ne_empty_zmset[simp]: "{#x#}⇩z ≠ {#}⇩z" and
empty_ne_singleton_zmset[simp]: "{#}⇩z ≠ {#x#}⇩z"
by (auto dest!: arg_cong2[of _ _ x _ zcount])
lemma
singleton_ne_uminus_singleton_zmset[simp]: "{#x#}⇩z ≠ - {#y#}⇩z" and
uminus_singleton_ne_singleton_zmset[simp]: "- {#x#}⇩z ≠ {#y#}⇩z"
by (auto dest!: arg_cong2[of _ _ x x zcount] split: if_splits)
subsubsection ‹Conversion to Set and Membership›
definition set_zmset :: "'a zmultiset ⇒ 'a set" where
"set_zmset M = {x. zcount M x ≠ 0}"
abbreviation elem_zmset :: "'a ⇒ 'a zmultiset ⇒ bool" where
"elem_zmset a M ≡ a ∈ set_zmset M"
notation
elem_zmset ("'(∈#⇩z')") and
elem_zmset ("(_/ ∈#⇩z _)" [51, 51] 50)
notation (ASCII)
elem_zmset ("'(:#z')") and
elem_zmset ("(_/ :#z _)" [51, 51] 50)
abbreviation not_elem_zmset :: "'a ⇒ 'a zmultiset ⇒ bool" where
"not_elem_zmset a M ≡ a ∉ set_zmset M"
notation
not_elem_zmset ("'(∉#⇩z')") and
not_elem_zmset ("(_/ ∉#⇩z _)" [51, 51] 50)
notation (ASCII)
not_elem_zmset ("'(~:#z')") and
not_elem_zmset ("(_/ ~:#z _)" [51, 51] 50)
context
begin
qualified abbreviation Ball :: "'a zmultiset ⇒ ('a ⇒ bool) ⇒ bool" where
"Ball M ≡ Set.Ball (set_zmset M)"
qualified abbreviation Bex :: "'a zmultiset ⇒ ('a ⇒ bool) ⇒ bool" where
"Bex M ≡ Set.Bex (set_zmset M)"
end
syntax
"_ZMBall" :: "pttrn ⇒ 'a set ⇒ bool ⇒ bool" ("(3∀_∈#⇩z_./ _)" [0, 0, 10] 10)
"_ZMBex" :: "pttrn ⇒ 'a set ⇒ bool ⇒ bool" ("(3∃_∈#⇩z_./ _)" [0, 0, 10] 10)
syntax (ASCII)
"_ZMBall" :: "pttrn ⇒ 'a set ⇒ bool ⇒ bool" ("(3∀_:#⇩z_./ _)" [0, 0, 10] 10)
"_ZMBex" :: "pttrn ⇒ 'a set ⇒ bool ⇒ bool" ("(3∃_:#⇩z_./ _)" [0, 0, 10] 10)
translations
"∀x∈#⇩zA. P" ⇌ "CONST Signed_Multiset.Ball A (λx. P)"
"∃x∈#⇩zA. P" ⇌ "CONST Signed_Multiset.Bex A (λx. P)"
lemma zcount_eq_zero_iff: "zcount M x = 0 ⟷ x ∉#⇩z M"
by (auto simp add: set_zmset_def)
lemma not_in_iff_zmset: "x ∉#⇩z M ⟷ zcount M x = 0"
by (auto simp add: zcount_eq_zero_iff)
lemma zcount_ne_zero_iff[simp]: "zcount M x ≠ 0 ⟷ x ∈#⇩z M"
by (auto simp add: set_zmset_def)
lemma zcount_inI:
assumes "zcount M x = 0 ⟹ False"
shows "x ∈#⇩z M"
proof (rule ccontr)
assume "x ∉#⇩z M"
with assms show False by (simp add: not_in_iff_zmset)
qed
lemma set_zmset_empty[simp]: "set_zmset {#}⇩z = {}"
by (simp add: set_zmset_def)
lemma set_zmset_single: "set_zmset {#b#}⇩z = {b}"
by (simp add: set_zmset_def)
lemma set_zmset_eq_empty_iff[simp]: "set_zmset M = {} ⟷ M = {#}⇩z"
by (auto simp add: zmultiset_eq_iff zcount_eq_zero_iff)
lemma finite_count_ne: "finite {x. count M x ≠ count N x}"
proof -
have "{x. count M x ≠ count N x} ⊆ set_mset M ∪ set_mset N"
by (auto simp: not_in_iff)
moreover have "finite (set_mset M ∪ set_mset N)"
by (rule finite_UnI[OF finite_set_mset finite_set_mset])
ultimately show ?thesis
by (rule finite_subset)
qed
lemma finite_set_zmset[iff]: "finite (set_zmset M)"
unfolding set_zmset_def by transfer (auto intro: finite_count_ne)
lemma zmultiset_nonemptyE[elim]:
assumes "A ≠ {#}⇩z"
obtains x where "x ∈#⇩z A"
proof -
have "∃x. x ∈#⇩z A"
by (rule ccontr) (insert assms, auto)
with that show ?thesis
by blast
qed
subsubsection ‹Union›
lemma zcount_union[simp]: "zcount (M + N) a = zcount M a + zcount N a"
by transfer auto
lemma union_add_left_zmset[simp]: "add_zmset a A + B = add_zmset a (A + B)"
by (auto simp: zmultiset_eq_iff)
lemma union_zmset_add_zmset_right[simp]: "A + add_zmset a B = add_zmset a (A + B)"
by (auto simp: zmultiset_eq_iff)
lemma add_zmset_add_single: ‹add_zmset a A = A + {#a#}⇩z›
by (subst union_zmset_add_zmset_right, subst add.comm_neutral) (rule refl)
subsubsection ‹Difference›
lemma zcount_diff[simp]: "zcount (M - N) a = zcount M a - zcount N a"
by transfer auto
lemma add_zmset_diff_bothsides: ‹add_zmset a M - add_zmset a A = M - A›
by (auto simp: zmultiset_eq_iff)
lemma in_diff_zcount: "a ∈#⇩z M - N ⟷ zcount N a ≠ zcount M a"
by (fastforce simp: set_zmset_def)
lemma diff_add_zmset:
fixes M N Q :: "'a zmultiset"
shows "M - (N + Q) = M - N - Q"
by (rule sym) (fact diff_diff_add)
lemma insert_Diff_zmset[simp]: "add_zmset x (M - {#x#}⇩z) = M"
by (clarsimp simp: zmultiset_eq_iff)
lemma diff_union_swap_zmset: "add_zmset b (M - {#a#}⇩z) = add_zmset b M - {#a#}⇩z"
by (auto simp add: zmultiset_eq_iff)
lemma diff_add_zmset_swap[simp]: "add_zmset b M - A = add_zmset b (M - A)"
by (auto simp add: zmultiset_eq_iff)
lemma diff_diff_add_zmset[simp]: "(M :: 'a zmultiset) - N - P = M - (N + P)"
by (rule diff_diff_add)
lemma zmset_add[elim?]:
obtains B where "A = add_zmset a B"
proof -
have "A = add_zmset a (A - {#a#}⇩z)"
by simp
with that show thesis .
qed
subsubsection ‹Equality of Signed Multisets›
lemma single_eq_single_zmset[simp]: "{#a#}⇩z = {#b#}⇩z ⟷ a = b"
by (auto simp add: zmultiset_eq_iff)
lemma multi_self_add_other_not_self_zmset[simp]: "M = add_zmset x M ⟷ False"
by (auto simp add: zmultiset_eq_iff)
lemma add_zmset_remove_trivial: ‹add_zmset x M - {#x#}⇩z = M›
by simp
lemma diff_single_eq_union_zmset: "M - {#x#}⇩z = N ⟷ M = add_zmset x N"
by auto
lemma union_single_eq_diff_zmset: "add_zmset x M = N ⟹ M = N - {#x#}⇩z"
unfolding add_zmset_add_single[of _ M] by (fact add_implies_diff)
lemma add_zmset_eq_conv_diff:
"add_zmset a M = add_zmset b N ⟷
M = N ∧ a = b ∨ M = add_zmset b (N - {#a#}⇩z) ∧ N = add_zmset a (M - {#b#}⇩z)"
by (simp add: zmultiset_eq_iff) fastforce
lemma add_zmset_eq_conv_ex:
"(add_zmset a M = add_zmset b N) =
(M = N ∧ a = b ∨ (∃K. M = add_zmset b K ∧ N = add_zmset a K))"
by (auto simp add: add_zmset_eq_conv_diff)
lemma multi_member_split: "∃A. M = add_zmset x A"
by (rule exI[where x = "M - {#x#}⇩z"]) simp
subsection ‹Conversions from and to Multisets›
lift_definition zmset_of :: "'a multiset ⇒ 'a zmultiset" is "λf. (Abs_multiset f, {#})" .
lemma zmset_of_inject[simp]: "zmset_of M = zmset_of N ⟷ M = N"
by (simp add: zmset_of_def, transfer', auto simp: equiv_zmset_def)
lemma zmset_of_empty[simp]: "zmset_of {#} = {#}⇩z"
by (simp add: zmset_of_def zero_zmultiset_def)
lemma zmset_of_add_mset[simp]: "zmset_of (add_mset x M) = add_zmset x (zmset_of M)"
by transfer (auto simp: equiv_zmset_def add_mset_def cong: if_cong)
lemma zcount_of_mset[simp]: "zcount (zmset_of M) x = int (count M x)"
by (induct M) auto
lemma zmset_of_plus: "zmset_of (M + N) = zmset_of M + zmset_of N"
by (transfer, auto simp: equiv_zmset_def eq_onp_same_args plus_multiset.abs_eq)+
lift_definition mset_pos :: "'a zmultiset ⇒ 'a multiset" is "λ(Mp, Mn). count (Mp - Mn)"
by (auto simp add: equiv_zmset_def simp flip: set_mset_diff)
(metis add.commute add_diff_cancel_right)
lift_definition mset_neg :: "'a zmultiset ⇒ 'a multiset" is "λ(Mp, Mn). count (Mn - Mp)"
by (auto simp add: equiv_zmset_def simp flip: set_mset_diff)
(metis add.commute add_diff_cancel_right)
lemma
zmset_of_inverse[simp]: "mset_pos (zmset_of M) = M" and
minus_zmset_of_inverse[simp]: "mset_neg (- zmset_of M) = M"
by (transfer, simp)+
lemma neg_zmset_pos[simp]: "mset_neg (zmset_of M) = {#}"
by (rule zmset_of_inject[THEN iffD1], simp, transfer, auto simp: equiv_zmset_def)+
lemma
count_mset_pos[simp]: "count (mset_pos M) x = nat (zcount M x)" and
count_mset_neg[simp]: "count (mset_neg M) x = nat (- zcount M x)"
by (transfer; auto)+
lemma
mset_pos_empty[simp]: "mset_pos {#}⇩z = {#}" and
mset_neg_empty[simp]: "mset_neg {#}⇩z = {#}"
by (rule multiset_eqI, simp)+
lemma
mset_pos_singleton[simp]: "mset_pos {#x#}⇩z = {#x#}" and
mset_neg_singleton[simp]: "mset_neg {#x#}⇩z = {#}"
by (rule multiset_eqI, simp)+
lemma
mset_pos_neg_partition: "M = zmset_of (mset_pos M) - zmset_of (mset_neg M)" and
mset_pos_as_neg: "zmset_of (mset_pos M) = zmset_of (mset_neg M) + M" and
mset_neg_as_pos: "zmset_of (mset_neg M) = zmset_of (mset_pos M) - M"
by (rule zmultiset_eqI, simp)+
lemma mset_pos_uminus[simp]: "mset_pos (- A) = mset_neg A"
by (rule multiset_eqI) simp
lemma mset_neg_uminus[simp]: "mset_neg (- A) = mset_pos A"
by (rule multiset_eqI) simp
lemma mset_pos_plus[simp]:
"mset_pos (A + B) = (mset_pos A - mset_neg B) + (mset_pos B - mset_neg A)"
by (rule multiset_eqI) simp
lemma mset_neg_plus[simp]:
"mset_neg (A + B) = (mset_neg A - mset_pos B) + (mset_neg B - mset_pos A)"
by (rule multiset_eqI) simp
lemma mset_pos_diff[simp]:
"mset_pos (A - B) = (mset_pos A - mset_pos B) + (mset_neg B - mset_neg A)"
by (rule mset_pos_plus[of A "- B", simplified])
lemma mset_neg_diff[simp]:
"mset_neg (A - B) = (mset_neg A - mset_neg B) + (mset_pos B - mset_pos A)"
by (rule mset_neg_plus[of A "- B", simplified])
lemma mset_pos_neg_dual:
"mset_pos a + mset_pos b + (mset_neg a - mset_pos b) + (mset_neg b - mset_pos a) =
mset_neg a + mset_neg b + (mset_pos a - mset_neg b) + (mset_pos b - mset_neg a)"
using [[linarith_split_limit = 20]] by (rule multiset_eqI) simp
lemma decompose_zmset_of2:
obtains A B C where
"M = zmset_of A + C" and
"N = zmset_of B + C"
proof
let ?A = "zmset_of (mset_pos M + mset_neg N)"
let ?B = "zmset_of (mset_pos N + mset_neg M)"
let ?C = "- (zmset_of (mset_neg M) + zmset_of (mset_neg N))"
show "M = ?A + ?C"
by (simp add: zmset_of_plus mset_pos_neg_partition)
show "N = ?B + ?C"
by (simp add: zmset_of_plus diff_add_zmset mset_pos_neg_partition)
qed
subsubsection ‹Pointwise Ordering Induced by @{const zcount}›
definition subseteq_zmset :: "'a zmultiset ⇒ 'a zmultiset ⇒ bool" (infix "⊆#⇩z" 50) where
"A ⊆#⇩z B ⟷ (∀a. zcount A a ≤ zcount B a)"
definition subset_zmset :: "'a zmultiset ⇒ 'a zmultiset ⇒ bool" (infix "⊂#⇩z" 50) where
"A ⊂#⇩z B ⟷ A ⊆#⇩z B ∧ A ≠ B"
abbreviation (input)
supseteq_zmset :: "'a zmultiset ⇒ 'a zmultiset ⇒ bool" (infix "⊇#⇩z" 50)
where
"supseteq_zmset A B ≡ B ⊆#⇩z A"
abbreviation (input)
supset_zmset :: "'a zmultiset ⇒ 'a zmultiset ⇒ bool" (infix "⊃#⇩z" 50)
where
"supset_zmset A B ≡ B ⊂#⇩z A"
notation (input)
subseteq_zmset (infix "⊆#⇩z" 50) and
supseteq_zmset (infix "⊇#⇩z" 50)
notation (ASCII)
subseteq_zmset (infix "⊆#⇩z" 50) and
subset_zmset (infix "⊂#⇩z" 50) and
supseteq_zmset (infix "⊇#⇩z" 50) and
supset_zmset (infix ">#⇩z" 50)