header {* More properties of maps plus map disjuction. *} (* Author: Rafal Kolanski, NICTA / CSE@UNSW *) theory MapExtra imports Main begin text {* BEWARE: we are not interested in using the @{term "dom x \ dom y = {}"} rules from Map for our separation logic proofs. As such, we overwrite the Map rules where that form of disjointness is in the assumption conflicts with a name we want to use with @{text "\"}. *} text {* A note on naming: Anything not involving heap disjuction can potentially be incorporated directly into Map.thy, thus uses @{text "m"}. Anything involving heap disjunction is not really mergeable with Map, is destined for use in separation logic, and hence uses @{text "h"} *} text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} text {* Things that should go into Option Type *} text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} text {* Misc option lemmas *} lemma None_not_eq: "(None \ x) = (\y. x = Some y)" by (cases x) auto lemma None_com: "(None = x) = (x = None)" by fast lemma Some_com: "(Some y = x) = (x = Some y)" by fast text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} text {* Things that should go into Map.thy *} text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} text {* Map intersection: set of all keys for which the maps agree. *} definition map_inter :: "('a \ 'b) \ ('a \ 'b) \ 'a set" (infixl "\\<^isub>m" 70) where "m\<^isub>1 \\<^isub>m m\<^isub>2 \ {x \ dom m\<^isub>1. m\<^isub>1 x = m\<^isub>2 x}" text {* Map restriction via domain subtraction *} definition sub_restrict_map :: "('a \ 'b) => 'a set => ('a \ 'b)" (infixl "`-" 110) where "m `- S \ (\x. if x \ S then None else m x)" subsection {* Properties of maps not related to restriction *} lemma empty_forall_equiv: "(m = empty) = (\x. m x = None)" by (fastsimp intro!: ext) lemma map_le_empty2 [simp]: "(m \\<^sub>m empty) = (m = empty)" by (auto simp: map_le_def intro: ext) lemma dom_iff: "(\y. m x = Some y) = (x \ dom m)" by auto lemma non_dom_eval: "x \ dom m \ m x = None" by auto lemma non_dom_eval_eq: "x \ dom m = (m x = None)" by auto lemma map_add_same_left_eq: "m\<^isub>1 = m\<^isub>1' \ (m\<^isub>0 ++ m\<^isub>1 = m\<^isub>0 ++ m\<^isub>1')" by simp lemma map_add_left_cancelI [intro!]: "m\<^isub>1 = m\<^isub>1' \ m\<^isub>0 ++ m\<^isub>1 = m\<^isub>0 ++ m\<^isub>1'" by simp lemma dom_empty_is_empty: "(dom m = {}) = (m = empty)" proof (rule iffI) assume a: "dom m = {}" { assume "m \ empty" hence "dom m \ {}" by - (subst (asm) empty_forall_equiv, simp add: dom_def) hence False using a by blast } thus "m = empty" by blast next assume a: "m = empty" thus "dom m = {}" by simp qed lemma map_add_dom_eq: "dom m = dom m' \ m ++ m' = m'" by (rule ext) (auto simp: map_add_def split: option.splits) lemma map_add_right_dom_eq: "\ m\<^isub>0 ++ m\<^isub>1 = m\<^isub>0' ++ m\<^isub>1'; dom m\<^isub>1 = dom m\<^isub>1' \ \ m\<^isub>1 = m\<^isub>1'" unfolding map_add_def by (rule ext, rule ccontr, drule_tac x=x in fun_cong, clarsimp split: option.splits, drule sym, drule sym, force+) lemma map_le_same_dom_eq: "\ m\<^isub>0 \\<^sub>m m\<^isub>1 ; dom m\<^isub>0 = dom m\<^isub>1 \ \ m\<^isub>0 = m\<^isub>1" by (auto intro!: ext simp: map_le_def elim!: ballE) subsection {* Properties of map restriction *} lemma restrict_map_cancel: "(m |` S = m |` T) = (dom m \ S = dom m \ T)" by (fastsimp intro: set_ext ext dest: fun_cong simp: restrict_map_def None_not_eq split: split_if_asm) lemma map_add_restricted_self [simp]: "m ++ m |` S = m" by (auto intro: ext simp: restrict_map_def map_add_def split: option.splits) lemma map_add_restrict_dom_right [simp]: "(m ++ m') |` dom m' = m'" by (rule ext, auto simp: restrict_map_def map_add_def split: option.splits) lemma restrict_map_UNIV [simp]: "m |` UNIV = m" by (simp add: restrict_map_def) lemma restrict_map_dom: "S = dom m \ m |` S = m" by (auto intro!: ext simp: restrict_map_def None_not_eq) lemma restrict_map_subdom: "dom m \ S \ m |` S = m" by (fastsimp simp: restrict_map_def None_com intro: ext) lemma map_add_restrict: "(m\<^isub>0 ++ m\<^isub>1) |` S = ((m\<^isub>0 |` S) ++ (m\<^isub>1 |` S))" by (force simp: map_add_def restrict_map_def intro: ext) lemma map_le_restrict: "m \\<^sub>m m' \ m = m' |` dom m" by (force simp: map_le_def restrict_map_def None_com intro: ext) lemma restrict_map_le: "m |` S \\<^sub>m m" by (auto simp: map_le_def) lemma restrict_map_remerge: "\ S \ T = {} \ \ m |` S ++ m |` T = m |` (S \ T)" by (rule ext, clarsimp simp: restrict_map_def map_add_def split: option.splits) lemma restrict_map_empty: "dom m \ S = {} \ m |` S = empty" by (fastsimp simp: restrict_map_def intro: ext) lemma map_add_restrict_comp_right [simp]: "(m |` S ++ m |` (UNIV - S)) = m" by (force simp: map_add_def restrict_map_def split: option.splits intro: ext) lemma map_add_restrict_comp_right_dom [simp]: "(m |` S ++ m |` (dom m - S)) = m" by (auto simp: map_add_def restrict_map_def split: option.splits intro!: ext) lemma map_add_restrict_comp_left [simp]: "(m |` (UNIV - S) ++ m |` S) = m" by (subst map_add_comm, auto) lemma restrict_self_UNIV: "m |` (dom m - S) = m |` (UNIV - S)" by (auto intro!: ext simp: restrict_map_def) lemma map_add_restrict_nonmember_right: "x \ dom m' \ (m ++ m') |` {x} = m |` {x}" by (rule ext, auto simp: restrict_map_def map_add_def split: option.splits) lemma map_add_restrict_nonmember_left: "x \ dom m \ (m ++ m') |` {x} = m' |` {x}" by (rule ext, auto simp: restrict_map_def map_add_def split: option.splits) lemma map_add_restrict_right: "x \ dom m' \ (m ++ m') |` x = m' |` x" by (rule ext, auto simp: restrict_map_def map_add_def split: option.splits) lemma restrict_map_compose: "\ S \ T = dom m ; S \ T = {} \ \ m |` S ++ m |` T = m" by (fastsimp intro: ext simp: map_add_def restrict_map_def) lemma map_le_dom_subset_restrict: "\ m' \\<^sub>m m; dom m' \ S \ \ m' \\<^sub>m (m |` S)" by (force simp: restrict_map_def map_le_def) lemma map_le_dom_restrict_sub_add: "m' \\<^sub>m m \ m |` (dom m - dom m') ++ m' = m" by (auto simp: None_com map_add_def restrict_map_def map_le_def split: option.splits intro!: ext) (force simp: Some_com)+ lemma subset_map_restrict_sub_add: "T \ S \ m |` (S - T) ++ m |` T = m |` S" by (auto simp: restrict_map_def map_add_def intro!: ext split: option.splits) lemma restrict_map_sub_union: "m |` (dom m - (S \ T)) = (m |` (dom m - T)) |` (dom m - S)" by (auto intro!: ext simp: restrict_map_def) lemma prod_restrict_map_add: "\ S \ T = U; S \ T = {} \ \ m |` (X \ S) ++ m |` (X \ T) = m |` (X \ U)" by (auto simp: map_add_def restrict_map_def intro!: ext split: option.splits) text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} text {* Things that should NOT go into Map.thy *} text {* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ *} section {* Definitions *} text {* Map disjuction *} definition map_disj :: "('a \ 'b) \ ('a \ 'b) \ bool" (infix "\" 51) where "h\<^isub>0 \ h\<^isub>1 \ dom h\<^isub>0 \ dom h\<^isub>1 = {}" declare None_not_eq [simp] section {* Properties of @{term "sub_restrict_map"} *} lemma restrict_map_sub_disj: "h |` S \ h `- S" by (fastsimp simp: sub_restrict_map_def restrict_map_def map_disj_def split: option.splits split_if_asm) lemma restrict_map_sub_add: "h |` S ++ h `- S = h" by (fastsimp simp: sub_restrict_map_def restrict_map_def map_add_def split: option.splits split_if intro: ext) section {* Properties of map disjunction *} lemma map_disj_empty_right [simp]: "h \ empty" by (simp add: map_disj_def) lemma map_disj_empty_left [simp]: "empty \ h" by (simp add: map_disj_def) lemma map_disj_com: "h\<^isub>0 \ h\<^isub>1 = h\<^isub>1 \ h\<^isub>0" by (simp add: map_disj_def, fast) lemma map_disjD: "h\<^isub>0 \ h\<^isub>1 \ dom h\<^isub>0 \ dom h\<^isub>1 = {}" by (simp add: map_disj_def) lemma map_disjI: "dom h\<^isub>0 \ dom h\<^isub>1 = {} \ h\<^isub>0 \ h\<^isub>1" by (simp add: map_disj_def) subsection {* Map associativity-commutativity based on map disjuction *} lemma map_add_com: "h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 ++ h\<^isub>1 = h\<^isub>1 ++ h\<^isub>0" by (drule map_disjD, rule map_add_comm, force) lemma map_add_left_commute: "h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 ++ (h\<^isub>1 ++ h\<^isub>2) = h\<^isub>1 ++ (h\<^isub>0 ++ h\<^isub>2)" by (simp add: map_add_com map_disj_com map_add_assoc) lemma map_add_disj: "h\<^isub>0 \ (h\<^isub>1 ++ h\<^isub>2) = (h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 \ h\<^isub>2)" by (simp add: map_disj_def, fast) lemma map_add_disj': "(h\<^isub>1 ++ h\<^isub>2) \ h\<^isub>0 = (h\<^isub>1 \ h\<^isub>0 \ h\<^isub>2 \ h\<^isub>0)" by (simp add: map_disj_def, fast) text {* We redefine @{term "map_add"} associativity to bind to the right, which seems to be the more common case. Note that when a theory includes Map again, @{text "map_add_assoc"} will return to the simpset and will cause infinite loops if its symmetric counterpart is added (e.g. via @{text "map_add_ac"}) *} declare map_add_assoc [simp del] text {* Since the associativity-commutativity of @{term "map_add"} relies on map disjunction, we include some basic rules into the ac set. *} lemmas map_add_ac = map_add_assoc[symmetric] map_add_com map_disj_com map_add_left_commute map_add_disj map_add_disj' subsection {* Basic properties *} lemma map_disj_None_right: "\ h\<^isub>0 \ h\<^isub>1 ; x \ dom h\<^isub>0 \ \ h\<^isub>1 x = None" by (auto simp: map_disj_def dom_def) lemma map_disj_None_left: "\ h\<^isub>0 \ h\<^isub>1 ; x \ dom h\<^isub>1 \ \ h\<^isub>0 x = None" by (auto simp: map_disj_def dom_def) lemma map_disj_None_left': "\ h\<^isub>0 x = Some y ; h\<^isub>1 \ h\<^isub>0 \ \ h\<^isub>1 x = None " by (auto simp: map_disj_def) lemma map_disj_None_right': "\ h\<^isub>1 x = Some y ; h\<^isub>1 \ h\<^isub>0 \ \ h\<^isub>0 x = None " by (auto simp: map_disj_def) subsection {* Map disjunction and addition *} lemma map_add_eval_left: "\ x \ dom h ; h \ h' \ \ (h ++ h') x = h x" by (auto dest!: map_disj_None_right simp: map_add_def cong: option.case_cong) lemma map_add_eval_right: "\ x \ dom h' ; h \ h' \ \ (h ++ h') x = h' x" by (auto elim!: map_disjD simp: map_add_comm map_add_eval_left map_disj_com) lemma map_add_eval_left': "\ x \ dom h' ; h \ h' \ \ (h ++ h') x = h x" by (clarsimp simp: map_disj_def map_add_def split: option.splits) lemma map_add_eval_right': "\ x \ dom h ; h \ h' \ \ (h ++ h') x = h' x" by (clarsimp simp: map_disj_def map_add_def split: option.splits) lemma map_add_left_dom_eq: assumes eq: "h\<^isub>0 ++ h\<^isub>1 = h\<^isub>0' ++ h\<^isub>1'" assumes etc: "h\<^isub>0 \ h\<^isub>1" "h\<^isub>0' \ h\<^isub>1'" "dom h\<^isub>0 = dom h\<^isub>0'" shows "h\<^isub>0 = h\<^isub>0'" proof - from eq have "h\<^isub>1 ++ h\<^isub>0 = h\<^isub>1' ++ h\<^isub>0'" using etc by (simp add: map_add_ac) thus ?thesis using etc by (fastsimp elim!: map_add_right_dom_eq simp: map_add_ac) qed lemma map_add_left_eq: assumes eq: "h\<^isub>0 ++ h = h\<^isub>1 ++ h" assumes disj: "h\<^isub>0 \ h" "h\<^isub>1 \ h" shows "h\<^isub>0 = h\<^isub>1" proof (rule ext) fix x from eq have eq': "(h\<^isub>0 ++ h) x = (h\<^isub>1 ++ h) x" by (auto intro!: ext) { assume "x \ dom h" hence "h\<^isub>0 x = h\<^isub>1 x" using disj by (simp add: map_disj_None_left) } moreover { assume "x \ dom h" hence "h\<^isub>0 x = h\<^isub>1 x" using disj eq' by (simp add: map_add_eval_left') } ultimately show "h\<^isub>0 x = h\<^isub>1 x" by cases qed lemma map_add_right_eq: "\h ++ h\<^isub>0 = h ++ h\<^isub>1; h\<^isub>0 \ h; h\<^isub>1 \ h\ \ h\<^isub>0 = h\<^isub>1" by (rule_tac h=h in map_add_left_eq, auto simp: map_add_ac) lemma map_disj_add_eq_dom_right_eq: assumes merge: "h\<^isub>0 ++ h\<^isub>1 = h\<^isub>0' ++ h\<^isub>1'" and d: "dom h\<^isub>0 = dom h\<^isub>0'" and ab_disj: "h\<^isub>0 \ h\<^isub>1" and cd_disj: "h\<^isub>0' \ h\<^isub>1'" shows "h\<^isub>1 = h\<^isub>1'" proof (rule ext) fix x from merge have merge_x: "(h\<^isub>0 ++ h\<^isub>1) x = (h\<^isub>0' ++ h\<^isub>1') x" by simp with d ab_disj cd_disj show "h\<^isub>1 x = h\<^isub>1' x" by - (case_tac "h\<^isub>1 x", case_tac "h\<^isub>1' x", simp, fastsimp simp: map_disj_def, case_tac "h\<^isub>1' x", clarsimp, simp add: Some_com, force simp: map_disj_def, simp) qed lemma map_disj_add_eq_dom_left_eq: assumes add: "h\<^isub>0 ++ h\<^isub>1 = h\<^isub>0' ++ h\<^isub>1'" and dom: "dom h\<^isub>1 = dom h\<^isub>1'" and disj: "h\<^isub>0 \ h\<^isub>1" "h\<^isub>0' \ h\<^isub>1'" shows "h\<^isub>0 = h\<^isub>0'" proof - have "h\<^isub>1 ++ h\<^isub>0 = h\<^isub>1' ++ h\<^isub>0'" using add disj by (simp add: map_add_ac) thus ?thesis using dom disj by - (rule map_disj_add_eq_dom_right_eq, auto simp: map_disj_com) qed lemma map_add_left_cancel: assumes disj: "h\<^isub>0 \ h\<^isub>1" "h\<^isub>0 \ h\<^isub>1'" shows "(h\<^isub>0 ++ h\<^isub>1 = h\<^isub>0 ++ h\<^isub>1') = (h\<^isub>1 = h\<^isub>1')" proof (rule iffI, rule ext) fix x assume "(h\<^isub>0 ++ h\<^isub>1) = (h\<^isub>0 ++ h\<^isub>1')" hence "(h\<^isub>0 ++ h\<^isub>1) x = (h\<^isub>0 ++ h\<^isub>1') x" by (auto intro!: ext) hence "h\<^isub>1 x = h\<^isub>1' x" using disj by - (cases "x \ dom h\<^isub>0", simp_all add: map_disj_None_right map_add_eval_right') thus "h\<^isub>1 x = h\<^isub>1' x" by (auto intro!: ext) qed auto lemma map_add_lr_disj: "\ h\<^isub>0 ++ h\<^isub>1 = h\<^isub>0' ++ h\<^isub>1'; h\<^isub>1 \ h\<^isub>1' \ \ dom h\<^isub>1 \ dom h\<^isub>0'" by (clarsimp simp: map_disj_def map_add_def, drule_tac x=x in fun_cong) (auto split: option.splits) subsection {* Map disjunction and updates *} lemma map_disj_update_left [simp]: "p \ dom h\<^isub>1 \ h\<^isub>0 \ h\<^isub>1(p \ v) = h\<^isub>0 \ h\<^isub>1" by (clarsimp simp add: map_disj_def, blast) lemma map_disj_update_right [simp]: "p \ dom h\<^isub>1 \ h\<^isub>1(p \ v) \ h\<^isub>0 = h\<^isub>1 \ h\<^isub>0" by (simp add: map_disj_com) lemma map_add_update_left: "\ h\<^isub>0 \ h\<^isub>1 ; p \ dom h\<^isub>0 \ \ (h\<^isub>0 ++ h\<^isub>1)(p \ v) = (h\<^isub>0(p \ v) ++ h\<^isub>1)" by (drule (1) map_disj_None_right) (auto intro: ext simp: map_add_def cong: option.case_cong) lemma map_add_update_right: "\ h\<^isub>0 \ h\<^isub>1 ; p \ dom h\<^isub>1 \ \ (h\<^isub>0 ++ h\<^isub>1)(p \ v) = (h\<^isub>0 ++ h\<^isub>1 (p \ v))" by (drule (1) map_disj_None_left) (auto intro: ext simp: map_add_def cong: option.case_cong) lemma map_add3_update: "\ h\<^isub>0 \ h\<^isub>1 ; h\<^isub>1 \ h\<^isub>2 ; h\<^isub>0 \ h\<^isub>2 ; p \ dom h\<^isub>0 \ \ (h\<^isub>0 ++ h\<^isub>1 ++ h\<^isub>2)(p \ v) = h\<^isub>0(p \ v) ++ h\<^isub>1 ++ h\<^isub>2" by (auto simp: map_add_update_left[symmetric] map_add_ac) subsection {* Map disjunction and @{term "map_le"} *} lemma map_le_override [simp]: "\ h \ h' \ \ h \\<^sub>m h ++ h'" by (auto simp: map_le_def map_add_def map_disj_def split: option.splits) lemma map_leI_left: "\ h = h\<^isub>0 ++ h\<^isub>1 ; h\<^isub>0 \ h\<^isub>1 \ \ h\<^isub>0 \\<^sub>m h" by auto lemma map_leI_right: "\ h = h\<^isub>0 ++ h\<^isub>1 ; h\<^isub>0 \ h\<^isub>1 \ \ h\<^isub>1 \\<^sub>m h" by auto lemma map_disj_map_le: "\ h\<^isub>0' \\<^sub>m h\<^isub>0; h\<^isub>0 \ h\<^isub>1 \ \ h\<^isub>0' \ h\<^isub>1" by (force simp: map_disj_def map_le_def) lemma map_le_on_disj_left: "\ h' \\<^sub>m h ; h\<^isub>0 \ h\<^isub>1 ; h' = h\<^isub>0 ++ h\<^isub>1 \ \ h\<^isub>0 \\<^sub>m h" unfolding map_le_def by (rule ballI, erule_tac x=a in ballE, auto simp: map_add_eval_left)+ lemma map_le_on_disj_right: "\ h' \\<^sub>m h ; h\<^isub>0 \ h\<^isub>1 ; h' = h\<^isub>1 ++ h\<^isub>0 \ \ h\<^isub>0 \\<^sub>m h" by (auto simp: map_le_on_disj_left map_add_ac) lemma map_le_add_cancel: "\ h\<^isub>0 \ h\<^isub>1 ; h\<^isub>0' \\<^sub>m h\<^isub>0 \ \ h\<^isub>0' ++ h\<^isub>1 \\<^sub>m h\<^isub>0 ++ h\<^isub>1" by (auto simp: map_le_def map_add_def map_disj_def split: option.splits) lemma map_le_override_bothD: assumes subm: "h\<^isub>0' ++ h\<^isub>1 \\<^sub>m h\<^isub>0 ++ h\<^isub>1" assumes disj': "h\<^isub>0' \ h\<^isub>1" assumes disj: "h\<^isub>0 \ h\<^isub>1" shows "h\<^isub>0' \\<^sub>m h\<^isub>0" unfolding map_le_def proof (rule ballI) fix a assume a: "a \ dom h\<^isub>0'" hence sumeq: "(h\<^isub>0' ++ h\<^isub>1) a = (h\<^isub>0 ++ h\<^isub>1) a" using subm unfolding map_le_def by auto from a have "a \ dom h\<^isub>1" using disj' by (auto dest!: map_disj_None_right) thus "h\<^isub>0' a = h\<^isub>0 a" using a sumeq disj disj' by (simp add: map_add_eval_left map_add_eval_left') qed lemma map_le_conv: "(h\<^isub>0' \\<^sub>m h\<^isub>0 \ h\<^isub>0' \ h\<^isub>0) = (\h\<^isub>1. h\<^isub>0 = h\<^isub>0' ++ h\<^isub>1 \ h\<^isub>0' \ h\<^isub>1 \ h\<^isub>0' \ h\<^isub>0)" unfolding map_le_def map_disj_def map_add_def by (rule iffI, clarsimp intro!: exI[where x="\x. if x \ dom h\<^isub>0' then h\<^isub>0 x else None"]) (fastsimp intro: ext intro: set_ext split: option.splits split_if_asm)+ lemma map_le_conv2: "h\<^isub>0' \\<^sub>m h\<^isub>0 = (\h\<^isub>1. h\<^isub>0 = h\<^isub>0' ++ h\<^isub>1 \ h\<^isub>0' \ h\<^isub>1)" by (case_tac "h\<^isub>0'=h\<^isub>0", insert map_le_conv, auto intro: exI[where x=empty]) subsection {* Map disjunction and restriction *} lemma map_disj_comp [simp]: "h\<^isub>0 \ h\<^isub>1 |` (UNIV - dom h\<^isub>0)" by (force simp: map_disj_def) lemma restrict_map_disj: "S \ T = {} \ h |` S \ h |` T" by (auto simp: map_disj_def restrict_map_def dom_def) lemma map_disj_restrict_dom [simp]: "h\<^isub>0 \ h\<^isub>1 |` (dom h\<^isub>1 - dom h\<^isub>0)" by (force simp: map_disj_def) lemma restrict_map_disj_dom_empty: "h \ h' \ h |` dom h' = empty" by (fastsimp simp: map_disj_def restrict_map_def intro: ext) lemma restrict_map_univ_disj_eq: "h \ h' \ h |` (UNIV - dom h') = h" by (rule ext, auto simp: map_disj_def restrict_map_def) lemma restrict_map_disj_dom: "h\<^isub>0 \ h\<^isub>1 \ h |` dom h\<^isub>0 \ h |` dom h\<^isub>1" by (auto simp: map_disj_def restrict_map_def dom_def) lemma map_add_restrict_dom_left: "h \ h' \ (h ++ h') |` dom h = h" by (rule ext, auto simp: restrict_map_def map_add_def dom_def map_disj_def split: option.splits) lemma restrict_map_disj_left: "h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 |` S \ h\<^isub>1" by (auto simp: map_disj_def) lemma restrict_map_disj_right: "h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 \ h\<^isub>1 |` S" by (auto simp: map_disj_def) lemmas restrict_map_disj_both = restrict_map_disj_right restrict_map_disj_left lemma map_dom_disj_restrict_right: "h\<^isub>0 \ h\<^isub>1 \ (h\<^isub>0 ++ h\<^isub>0') |` dom h\<^isub>1 = h\<^isub>0' |` dom h\<^isub>1" by (simp add: map_add_restrict restrict_map_empty map_disj_def) lemma restrict_map_on_disj: "h\<^isub>0' \ h\<^isub>1 \ h\<^isub>0 |` dom h\<^isub>0' \ h\<^isub>1" unfolding map_disj_def by auto lemma restrict_map_on_disj': "h\<^isub>0 \ h\<^isub>1 \ h\<^isub>0 \ h\<^isub>1 |` S" by (auto simp: map_disj_def map_add_def) lemma map_le_sub_dom: "\ h\<^isub>0 ++ h\<^isub>1 \\<^sub>m h ; h\<^isub>0 \ h\<^isub>1 \ \ h\<^isub>0 \\<^sub>m h |` (dom h - dom h\<^isub>1)" by (rule map_le_override_bothD, subst map_le_dom_restrict_sub_add) (auto elim: map_add_le_mapE simp: map_add_ac) lemma map_submap_break: "\ h \\<^sub>m h' \ \ h' = (h' |` (UNIV - dom h)) ++ h" by (fastsimp intro!: ext split: option.splits simp: map_le_restrict restrict_map_def map_le_def map_add_def dom_def) lemma map_add_disj_restrict_both: "\ h\<^isub>0 \ h\<^isub>1; S \ S' = {}; T \ T' = {} \ \ (h\<^isub>0 |` S) ++ (h\<^isub>1 |` T) \ (h\<^isub>0 |` S') ++ (h\<^isub>1 |` T')" by (auto simp: map_add_ac intro!: restrict_map_disj_both restrict_map_disj) end