Theory TypeEnvironment

Up to index of Isabelle/HOL/CoreSafe

theory TypeEnvironment
imports Main
begin

(*  Title:      TypeEnvironment
    Author:     Javier de Dios and Ricardo Peņa
    Copyright:  June 2008, Universidad Complutense de Madrid
*)

header {* Type Environment and operators *}

(*<*)
theory TypeEnvironment
imports Main 
begin
(*>*)

text{*
Non-functional algebraic types may be safe types s'', condemned types d'' or indanger
types r''.
*}

datatype Mark = s'' | d'' | r''

text{*
A type environment is a partial mapping from program variables to marks.
*}

types TypeEnvironment = "string \<rightharpoonup> Mark"

text{*
Some auxiliary predicates: 'unsafe' is true for condemned and in-danger types,
'safe' is true for safe types.
*}

constdefs unsafe :: "Mark option => bool"
"unsafe x ≡  (x = Some d'')  ∨ (x = Some r'')"

constdefs safe :: "Mark option => bool"
"safe x ≡  (x = Some s'')"

subsection {* Operators on type environments  *}

constdefs
unionEnv ::  "TypeEnvironment => TypeEnvironment => TypeEnvironment" 
"unionEnv Γ1 Γ2 ≡ (%x. if x: dom Γ1 then Γ1 x else Γ2 x)"

text{*
Operator +: Disjoint union of environments
*}

constdefs def_disjointUnionEnv ::  "TypeEnvironment => TypeEnvironment => bool"
"def_disjointUnionEnv Γ1 Γ2 ≡  dom Γ1 ∩ dom Γ2 = {}"

constdefs disjointUnionEnv ::  "TypeEnvironment => TypeEnvironment => TypeEnvironment" (infix "+" 100)
"Γ1 + Γ2 ≡ unionEnv Γ1 Γ2"

text{*
Operator $\otimes$ : It allows to join two non-disjoint environments provided they
map the common variables to the same types. 
*}

constdefs
def_nonDisjointUnionEnv :: "TypeEnvironment =>  TypeEnvironment => bool"
"def_nonDisjointUnionEnv Γ1 Γ2 ≡ (∀x ∈ dom Γ1 ∩ dom Γ2. Γ1 x = Γ2 x)"

constdefs
nonDisjointUnionEnv :: "TypeEnvironment => TypeEnvironment => TypeEnvironment" (infixl "⊗" 60)
"Γ1 ⊗ Γ2 ≡ unionEnv Γ1 Γ2"


text{*
Operator $\otimes$ : It allows to join n-non-disjoint environments provided they
map the common variables to the same types. 
*}

fun nonDisjointUnionEnvList :: "TypeEnvironment list => TypeEnvironment" where
  "nonDisjointUnionEnvList Γs = foldl nonDisjointUnionEnv empty Γs"

fun def_nonDisjointUnionEnvList :: "TypeEnvironment list => bool" where
  "def_nonDisjointUnionEnvList []         = True"

| "def_nonDisjointUnionEnvList (G#Gs) = (let Gs' = nonDisjointUnionEnvList Gs;
                                             def_Gs' = def_nonDisjointUnionEnvList Gs in 
                                             def_nonDisjointUnionEnv G Gs' ∧ def_Gs' )"


text{*
Operator $\oplus$ : It allows to join two non-disjoint environments provided they
map the common variables to the same safe types.
*}

constdefs 
def_nonDisjointUnionSafeEnv :: "TypeEnvironment => TypeEnvironment => bool"
"def_nonDisjointUnionSafeEnv Γ1 Γ2 ≡ (∀x ∈ dom Γ1 ∩ dom Γ2. safe (Γ1 x) ∧ safe (Γ2 x))"

constdefs
nonDisjointUnionSafeEnv :: "TypeEnvironment => TypeEnvironment => TypeEnvironment" (infixl "⊕" 60)
"Γ1 ⊕ Γ2 ≡ unionEnv Γ1 Γ2"

fun nonDisjointUnionSafeEnvList :: "TypeEnvironment list => TypeEnvironment" where
  "nonDisjointUnionSafeEnvList Γs = foldl nonDisjointUnionSafeEnv empty Γs"

fun def_nonDisjointUnionSafeEnvList :: "TypeEnvironment list => bool" where
  "def_nonDisjointUnionSafeEnvList []         = True"

| "def_nonDisjointUnionSafeEnvList (G#Gs) = (let Gs' = nonDisjointUnionSafeEnvList Gs;
                                             def_Gs' = def_nonDisjointUnionSafeEnvList Gs in 
                                             def_nonDisjointUnionSafeEnv G Gs' ∧ def_Gs' )"


text{*
Operator $\triangleright$ : This is used in rules for let. In the union $\Gamma$1 $\triangleright$ $\Gamma$2
not allowed that variables in L may have unsafe type in $\Gamma$1 . Also, variables
common to $\Gamma$2 and L may not have unsafe type in $\Gamma$2. Once well defined, in
environment  $\Gamma$1 $\triangleright$ $\Gamma$2 the types assigned in $\Gamma$2 to common 
variables, will prevail.
*}


constdefs
def_pp :: "TypeEnvironment => TypeEnvironment => string set => bool"
"def_pp Γ1 Γ2 L ≡
 (∀x. x ∈ dom Γ1 --> unsafe (Γ1 x) --> x ∉ L ∧ (x ∉ dom Γ2 ∨ (Γ2 x ≠ Some s'' ∧ Γ2 x ≠  Some d''))) ∧
 (∀x. x ∈ dom Γ2 ∧ 
          (Γ2 x = Some s'' ∨ Γ2 x =  Some d'') 
       --> x ∈ L)"

constdefs
pp :: "TypeEnvironment => TypeEnvironment => string set => TypeEnvironment"  ("_\<triangleright>_ _")
"Γ1 \<triangleright> Γ2 L ≡  (%x. (if x ∉ dom Γ1 ∨ (x ∈ dom Γ1 ∩ dom Γ2 ∧ safe (Γ1 x))
                     then Γ2 x else Γ1 x))"



text{*
Lemmas for unionEnv operator
*}

lemma empty_unionEnv: "unionEnv m empty = m"
apply (rule ext) 
by (simp add: unionEnv_def split: option.split add: dom_def)

lemma dom_empty_unionEnv: "dom (unionEnv m1 empty) = dom m1"
apply (subgoal_tac "unionEnv m1 empty = m1")
by (simp, rule empty_unionEnv)


text{*
Lemmas for disjointUnionEnv operator
*}

lemma empty_disjointUnionEnv: "disjointUnionEnv m empty = m"
by (simp add: disjointUnionEnv_def, rule empty_unionEnv)

lemma dom_empty_disjointUnionEnv: "dom (disjointUnionEnv m1 empty) = dom m1"
by (simp add: disjointUnionEnv_def, rule dom_empty_unionEnv)

lemma union_dom_disjointUnionEnv: 
 "def_disjointUnionEnv Γ1 Γ2 ==> dom (disjointUnionEnv Γ1 Γ2) = dom Γ1 ∪ dom Γ2"
apply (simp add: def_disjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def, auto)
by (split split_if_asm,simp,simp)

lemma dom_disjointUnionEnv_monotone:
  "dom (G + G') = dom G ∪  dom G'"
apply (simp add: disjointUnionEnv_def add: unionEnv_def, auto)
by (split split_if_asm, simp, simp)

text{*
Lemmas for nonDisjointUnionEnv operator
*}

lemma empty_nonDisjointUnionEnv :
  "empty ⊗ A = A"
by (simp add: nonDisjointUnionEnv_def add: unionEnv_def)

lemma refl_nonDisjointUnionEnv :
  "A ⊗ A = A"
by (simp add: nonDisjointUnionEnv_def add: unionEnv_def)


lemma list_induct3: 
  "[| P [] 0;
  !!x xs. P (x#xs) 0;
  !!i. P [] (Suc i);
   !!x xs i. P xs i  ==> P (x#xs) (Suc i) |]
 ==> P xs i"
by (induct xs arbitrary: i) (case_tac x, auto)+

lemma nonDisjointUnionEnv_conmutative: 
  "def_nonDisjointUnionEnv G G' ==> (G ⊗ G') = (G' ⊗ G)"
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
apply (rule ext)
by (simp add: def_nonDisjointUnionEnv_def,clarsimp)

lemma nonDisjointUnionEnv_assoc: 
  "(G1 ⊗ G2) ⊗  G3 = G1 ⊗ (G2 ⊗  G3)"
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
apply (rule ext, auto)
 apply (split split_if_asm, simp, simp)
 apply (split split_if_asm, simp,simp)
by (split split_if_asm, simp, simp add: dom_def)

lemma nonDisjointUnionEnv_disjointUnionEnv_assoc: 
  "(G1 ⊗ G2) +  G3 = G1 ⊗ (G2 +  G3)"
apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)
apply (rule ext, auto)
 apply (split split_if_asm, simp, simp)
 apply (split split_if_asm, simp,simp)
by (split split_if_asm, simp, simp add: dom_def)

lemma foldl_prop1: 
  "foldl op ⊗ (G' ⊗ G) Gs = G' ⊗ foldl op ⊗ G Gs"
apply (induct Gs arbitrary: G)
 apply simp
by (simp_all add: nonDisjointUnionEnv_assoc)

lemma foldl_prop2: 
  "foldl op ⊗ (G' ⊗ G) Gs + G'' = G' ⊗ foldl op ⊗ G Gs + G''"
apply (induct Gs arbitrary: G)
apply (simp_all add: nonDisjointUnionEnv_assoc)
by (rule nonDisjointUnionEnv_disjointUnionEnv_assoc)

lemma union_dom_nonDisjointUnionEnv:
" dom (A ⊗ B) = dom A ∪ dom B"
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def,auto)
by (split split_if_asm,simp_all)

lemma union_dom_nonDisjointUnionEnv_disjointUnionEnv:
" dom (A ⊗ B +  [x \<mapsto> m]) = dom A ∪ dom (B +  [x \<mapsto> m])"
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def, auto)
apply (split split_if_asm,simp)
by simp

lemma def_nonDisjointUnionEnvList_prop1:
"def_nonDisjointUnionEnvList (x # xs) --> def_nonDisjointUnionEnv x (foldl op ⊗ empty xs)"
by (simp add: Let_def)

lemma dom_foldl_monotone:
  " dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert)) = 
    dom (snd a) ∪  dom (foldl op ⊗ empty (map snd assert))"
apply (subgoal_tac "empty ⊗ snd a = snd a ⊗ empty",simp)
 apply (subgoal_tac "foldl op ⊗ (snd a ⊗ empty) (map snd assert) = 
                     (snd a) ⊗ foldl op ⊗ empty (map snd assert)",simp)
  apply (rule union_dom_nonDisjointUnionEnv)
 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd a)")
 apply (erule nonDisjointUnionEnv_conmutative)
by (simp add: def_nonDisjointUnionEnv_def)

lemma dom_foldl_disjointUnionEnv_monotone:
  " dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert) + [x \<mapsto> d'']) = 
    dom (snd a) ∪  dom (foldl op ⊗ empty (map snd assert)) ∪ dom  [x \<mapsto> d'']"
apply (subgoal_tac "empty ⊗ snd a = snd a ⊗ empty",simp)
 apply (subgoal_tac "foldl op ⊗ (snd a ⊗ empty) (map snd assert) = 
                     (snd a) ⊗ foldl op ⊗ empty (map snd assert)",simp)
  apply (subst dom_disjointUnionEnv_monotone)
  apply (subst union_dom_nonDisjointUnionEnv)
  apply simp
 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd a)")
 apply (erule nonDisjointUnionEnv_conmutative)
by (simp add: def_nonDisjointUnionEnv_def)


lemma dom_monotone:
" length assert > i ==> dom (snd (assert ! i)) ⊆ dom (foldl op ⊗ empty (map snd assert))"
apply (induct assert i rule: list_induct3, simp_all)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd x) (map snd xs)) = 
                     dom (snd x) ∪  dom (foldl op ⊗ empty (map snd xs))",simp)
apply blast
apply (rule dom_foldl_monotone)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd x) (map snd xs)) = 
                     dom (snd x) ∪  dom (foldl op ⊗ empty (map snd xs))",simp)
apply blast
by (rule dom_foldl_monotone)

lemma dom_monotone_foldl_nonDijointUnionEnv:
 "length assert > i ==> dom (snd (assert ! i)) ⊆ dom (foldl op ⊗ empty (map snd assert) + [x \<mapsto> d''])"
apply (induct assert i rule: list_induct3, simp_all)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd xa) (map snd xs) + [x \<mapsto> d'']) = 
                     dom (snd xa) ∪  dom (foldl op ⊗ empty (map snd xs)) ∪ dom [x \<mapsto> d'']",simp)
apply blast
apply (rule dom_foldl_disjointUnionEnv_monotone)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd xa) (map snd xs) + [x \<mapsto> d'']) = 
                     dom (snd xa) ∪  dom (foldl op ⊗ empty (map snd xs)) ∪ dom [x \<mapsto> d'']",simp)
 apply (subgoal_tac "dom (foldl op ⊗ empty (map snd xs) + [x \<mapsto> d'']) =
                     dom (foldl op ⊗ empty (map snd xs)) ∪ dom [x \<mapsto> d'']",simp)
  apply blast
 apply (rule dom_disjointUnionEnv_monotone)
by (rule dom_foldl_disjointUnionEnv_monotone)



lemma dom_Γi_subseteq_dom_Γ_case:
" length assert > 0 ==> 
  (∀i< length assert. dom (snd (assert ! i)) ⊆ 
                      dom (foldl op ⊗ empty (map snd assert)))"
apply (induct assert)
 apply simp
apply (case_tac "assert = []")
 apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def,simp)
apply (rule allI)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert)) = 
                     dom (snd a) ∪  dom (foldl op ⊗ empty (map snd assert))",simp)
 apply (case_tac i)
  apply (simp,blast)
 apply simp
 apply (erule_tac x="nat" in allE)
apply (blast,simp)
apply (subgoal_tac "empty ⊗ snd a = snd a ⊗ empty",simp)
 apply (subgoal_tac "foldl op ⊗ (snd a ⊗ empty) (map snd assert) = 
                     (snd a) ⊗ foldl op ⊗ empty (map snd assert)",simp)
  apply (rule union_dom_nonDisjointUnionEnv)
 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd a)")
 apply (erule nonDisjointUnionEnv_conmutative)
by (simp add: def_nonDisjointUnionEnv_def)


lemma dom_Γi_subseteq_dom_Γ_cased:
" length assert > 0 ==> 
  (∀i< length assert. dom (snd (assert ! i)) ⊆ dom (foldl op ⊗ empty (map snd assert) + [x \<mapsto> d'']))"
apply (induct assert)
 apply simp
apply (case_tac "assert = []")
 apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
 apply (simp add: disjointUnionEnv_def add: unionEnv_def, clarsimp)
apply (rule allI)
apply (subgoal_tac " dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert) + [x \<mapsto> d'']) = 
                     dom (snd a) ∪  dom (foldl op ⊗ empty (map snd assert) + [x \<mapsto> d''])",simp)
 apply (case_tac i)
  apply (simp,blast)
 apply simp
 apply (erule_tac x="nat" in allE)
apply (blast,simp)  
apply (subgoal_tac "empty ⊗ snd a = snd a ⊗ empty",simp)
 apply (subgoal_tac "foldl op ⊗ (snd a ⊗ empty) (map snd assert) + [x \<mapsto> d''] = 
                     (snd a) ⊗ foldl op ⊗ empty (map snd assert) + [x \<mapsto> d'']",simp)
  apply (rule union_dom_nonDisjointUnionEnv_disjointUnionEnv)
 apply (rule foldl_prop2)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd a)")
 apply (erule nonDisjointUnionEnv_conmutative)
by (simp add: def_nonDisjointUnionEnv_def)


lemma nonDisjointUnionEnv_prop1: 
  "(G ⊗ G') z = Some m ==> G z = Some m ∨ (z ∉ dom G ∧ G' z = Some m)"
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
by (split split_if_asm,simp_all)


lemma nonDisjointUnionEnv_prop2: 
  "[| def_nonDisjointUnionEnv G G'; (G ⊗ G') z = Some m |] 
  ==> G' z = Some m ∨ (z ∉ dom G' ∧ G z = Some m)"
apply (frule nonDisjointUnionEnv_conmutative,simp) 
by (erule nonDisjointUnionEnv_prop1)

lemma nonDisjointUnionEnv_prop5: 
  "[| x ∈ dom G; G x ≠ Some m |] ==> (G ⊗ G') x ≠ Some m"
by (simp add: nonDisjointUnionEnv_def add: unionEnv_def)

lemma nonDisjointUnionEnv_prop6: 
  "[| def_nonDisjointUnionEnv G G'; z ∈ dom G'; G' z ≠ Some m |] ==> (G ⊗ G') z ≠ Some m"
apply (simp add: def_nonDisjointUnionEnv_def)
apply (erule_tac x="z" in ballE)
 apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
by (simp add: nonDisjointUnionEnv_def add: unionEnv_def)

lemma nonDisjointUnionEnv_prop6_1: 
  "[| x ∈ dom G; G x = Some m |] ==> (G ⊗ G') x = Some m"
by (simp add: nonDisjointUnionEnv_def add: unionEnv_def)

lemma nonDisjointUnionEnv_prop6_2: 
  "[| def_nonDisjointUnionEnv G G'; G' z = Some m |] ==> (G ⊗ G') z = Some m"
apply (simp add: def_nonDisjointUnionEnv_def)
apply (erule_tac x="z" in ballE)
 apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
apply (simp add: nonDisjointUnionEnv_def add: unionEnv_def)
by (rule impI, simp, simp add: dom_def)


lemma Otimes_prop1:
  "i < length (map snd assert) --> 
   length (map snd assert) > 0 --> 
   def_nonDisjointUnionEnvList (map snd assert) -->  
   foldl op ⊗ empty (map snd assert) z = Some d'' -->
   z ∈ dom (snd (assert ! i)) -->
   (snd (assert ! i)) z = Some d''"
apply (induct assert i rule: list_induct3, simp_all)
 apply (intro impI)
 apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd x)") 
  prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
 apply (subgoal_tac "(empty ⊗ (snd x)) = ((snd x) ⊗ empty)" ,simp) 
  prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
 apply (subgoal_tac "foldl op ⊗ (snd x ⊗ empty) (map snd xs) = 
                     (snd x) ⊗ foldl op ⊗ empty (map snd xs)",simp)
  prefer 2 apply (rule foldl_prop1)
 apply (frule nonDisjointUnionEnv_prop1)
 apply (erule disjE) 
  apply (simp add: dom_def)
apply (simp,intro impI,simp)
apply (case_tac "xs=[]",simp)
apply (simp add: Let_def)
apply (elim conjE)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd x)")
 prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
apply (subgoal_tac "(empty ⊗ snd x) = (snd x ⊗ empty)",simp)
 prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
apply (subgoal_tac "foldl op ⊗ (snd x ⊗ empty) (map snd xs) = 
                    snd x ⊗ foldl op ⊗ empty (map snd xs)",simp)
 prefer 2 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnvList (snd x # (map snd xs)) --> 
                    def_nonDisjointUnionEnv (snd x) (foldl op ⊗ empty (map snd xs))",simp)
 prefer 2 apply (rule def_nonDisjointUnionEnvList_prop1)
apply (frule_tac G="snd x" and G'="foldl op ⊗ empty (map snd xs)" in nonDisjointUnionEnv_prop2,simp)
apply (erule disjE) 
 apply simp
apply (elim conjE)
apply (subgoal_tac " dom (snd (xs ! i)) ⊆ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply (rule dom_monotone,blast)
by blast

lemma Otimes_prop2 [rule_format]:
"  i < length (map snd assert) --> 
   length (map snd assert) > 0 --> 
   def_nonDisjointUnionEnvList (map snd assert) -->  
   x ∈ dom (snd (assert ! i)) -->
   snd (assert ! i) x ≠ Some s'' -->
   foldl op ⊗ empty (map snd assert) x ≠ Some s''"
apply (induct assert i rule: list_induct3, simp_all)
 apply (intro impI)
 apply (simp add: Let_def)
 apply (elim conjE)
 apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
  prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
 apply (subgoal_tac "(empty ⊗ (snd xa)) = ((snd xa) ⊗ empty)",simp)
  prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
 apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                     (snd xa) ⊗ foldl op ⊗ empty (map snd xs)",simp)
  prefer 2 apply (rule foldl_prop1)
 apply (rule nonDisjointUnionEnv_prop5,assumption+)
apply (intro impI,simp)
apply (case_tac "xs=[]",simp)
apply (simp add: Let_def)
apply (elim conjE)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
 prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
apply (subgoal_tac "(empty ⊗ snd xa) = (snd xa ⊗ empty)",simp)
 prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                    snd xa ⊗ foldl op ⊗ empty (map snd xs)",simp)
 prefer 2 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnvList (snd xa # (map snd xs)) --> 
                    def_nonDisjointUnionEnv (snd xa) (foldl op ⊗ empty (map snd xs))",simp)
 prefer 2 apply (rule def_nonDisjointUnionEnvList_prop1)
apply (subgoal_tac " dom (snd (xs ! i)) ⊆ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply (rule dom_monotone,simp)
apply (subgoal_tac "x ∈ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply blast
by (rule nonDisjointUnionEnv_prop6,assumption+)


lemma Otimes_prop3:
"  i < length (map snd assert) --> 
   length (map snd assert) > 0 --> 
   def_nonDisjointUnionEnvList (map snd assert) -->  
   snd (assert ! i) x = Some m -->
   foldl op ⊗ empty (map snd assert) x = Some m"
apply (induct assert i rule: list_induct3, simp_all)
 apply (intro impI)
 apply (simp add: Let_def)
 apply (elim conjE)
 apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
  prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
 apply (subgoal_tac "(empty ⊗ (snd xa)) = ((snd xa) ⊗ empty)",simp) 
  prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
 apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                     (snd xa) ⊗ foldl op ⊗ empty (map snd xs)",simp)
  prefer 2 apply (rule foldl_prop1)
 apply (rule nonDisjointUnionEnv_prop6_1, simp add: dom_def, assumption+)
apply (intro impI,simp)
apply (case_tac "xs=[]",simp)
apply (simp add: Let_def)
apply (elim conjE)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
 prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
apply (subgoal_tac "(empty ⊗ snd xa) = (snd xa ⊗ empty)",simp) 
 prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                    snd xa ⊗ foldl op ⊗ empty (map snd xs)",simp)
 prefer 2 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnvList (snd xa # (map snd xs)) --> 
                    def_nonDisjointUnionEnv (snd xa) (foldl op ⊗ empty (map snd xs))",simp)
 prefer 2 apply (rule def_nonDisjointUnionEnvList_prop1)
apply (subgoal_tac " dom (snd (xs ! i)) ⊆ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply (rule dom_monotone,simp)
apply (subgoal_tac "x ∈ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply blast
by (rule nonDisjointUnionEnv_prop6_2,assumption+)


lemma nonDisjointUnionEnv_disjointUnionEnv_prop1: 
  "[| x ∈ dom G; G x ≠ Some m |] ==> ((G ⊗ G') + G'') x ≠ Some m"
apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)
apply (rule impI, auto)
apply (split split_if_asm, simp add: dom_def)
by (simp add: dom_def)


lemma nonDisjointUnionEnv_disjointUnionEnv_prop2:
  "[| def_nonDisjointUnionEnv G G'; z ∈ dom G'; G' z ≠ Some m |] ==> ((G ⊗ G') + G'') z ≠ Some m"
apply (simp add: def_nonDisjointUnionEnv_def)
apply (erule_tac x="z" in ballE)
 apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def) 
 apply (rule impI, auto)
apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def) 
by (split split_if_asm, simp add: dom_def,auto)

lemma nonDisjointUnionEnv_disjointUnionEnv_prop3: 
  "[| x ∈ dom G; G x = Some m |] ==> ((G ⊗ G') + G'') x = Some m"
apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)
by (rule impI,auto)

lemma nonDisjointUnionEnv_disjointUnionEnv_prop4: 
  "[| def_nonDisjointUnionEnv G G'; G' z = Some m |] ==> ((G ⊗ G') + G'') z = Some m"
apply (simp add: def_nonDisjointUnionEnv_def)
apply (erule_tac x="z" in ballE)
 apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)
 apply (rule impI,auto)
apply (simp add: nonDisjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)
apply (split split_if_asm,auto)
by (split split_if_asm,auto) 


lemma Otimes_prop2_not_s [rule_format]:
"  i < length (map snd assert) --> 
   length (map snd assert) > 0 --> 
   def_nonDisjointUnionEnvList (map snd assert) -->  
   y ∈ dom (snd (assert ! i)) -->
   snd (assert ! i) y ≠ Some s'' -->
   (foldl op ⊗ empty (map snd assert) + [x \<mapsto> d'']) y ≠ Some s''"
apply (induct assert i rule: list_induct3, simp_all)
 apply (intro impI)
 apply (simp add: Let_def)
 apply (elim conjE)
 apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
  prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
 apply (subgoal_tac "(empty ⊗ (snd xa)) = ((snd xa) ⊗ empty)",simp)
  prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
 apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                     (snd xa) ⊗ foldl op ⊗ empty (map snd xs)",simp)
  prefer 2 apply (rule foldl_prop1)
 apply (rule nonDisjointUnionEnv_disjointUnionEnv_prop1,assumption+)
apply (intro impI,simp)
apply (case_tac "xs=[]",simp)
apply (simp add: Let_def)
apply (elim conjE)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xa)") 
 prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
apply (subgoal_tac "(empty ⊗ snd xa) = (snd xa ⊗ empty)",simp)
 prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
apply (subgoal_tac "foldl op ⊗ (snd xa ⊗ empty) (map snd xs) = 
                    snd xa ⊗ foldl op ⊗ empty (map snd xs)",simp)
 prefer 2 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnvList (snd xa # (map snd xs)) --> 
                    def_nonDisjointUnionEnv (snd xa) (foldl op ⊗ empty (map snd xs))",simp)
 prefer 2 apply (rule def_nonDisjointUnionEnvList_prop1)
apply (subgoal_tac " dom (snd (xs ! i)) ⊆ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply (rule dom_monotone,simp)
apply (subgoal_tac "y ∈ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply blast
apply (rule nonDisjointUnionEnv_disjointUnionEnv_prop2,assumption+)
by (simp add: disjointUnionEnv_def add: unionEnv_def)


lemma Otimes_prop4 [rule_format]:
"  i < length (map snd assert) --> 
   length (map snd assert) > 0 --> 
   def_nonDisjointUnionEnvList (map snd assert) -->  
   snd (assert ! i) xa = Some m -->
   (foldl op ⊗ empty (map snd assert) + [x \<mapsto> d'']) xa = Some m"
apply (induct assert i rule: list_induct3, simp_all)
 apply (intro impI)
 apply (simp add: Let_def)
 apply (elim conjE)
 apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xb)") 
  prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
 apply (subgoal_tac "(empty ⊗ (snd xb)) = ((snd xb) ⊗ empty)",simp) 
  prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
 apply (subgoal_tac "foldl op ⊗ (snd xb ⊗ empty) (map snd xs) = 
                     (snd xb) ⊗ foldl op ⊗ empty (map snd xs)",simp)
  prefer 2 apply (rule foldl_prop1)
 apply (rule nonDisjointUnionEnv_disjointUnionEnv_prop3, simp add: dom_def, assumption+)
apply (intro impI,simp)
apply (case_tac "xs=[]",simp)
apply (simp add: Let_def)
apply (elim conjE)
apply (subgoal_tac "def_nonDisjointUnionEnv empty (snd xb)") 
 prefer 2 apply (simp add: def_nonDisjointUnionEnv_def)
apply (subgoal_tac "(empty ⊗ snd xb) = (snd xb ⊗ empty)",simp) 
 prefer 2 apply (rule nonDisjointUnionEnv_conmutative,simp)
apply (subgoal_tac "foldl op ⊗ (snd xb ⊗ empty) (map snd xs) = 
                    snd xb ⊗ foldl op ⊗ empty (map snd xs)",simp)
 prefer 2 apply (rule foldl_prop1)
apply (subgoal_tac "def_nonDisjointUnionEnvList (snd xb # (map snd xs)) --> 
                    def_nonDisjointUnionEnv (snd xb) (foldl op ⊗ empty (map snd xs))",simp)
 prefer 2 apply (rule def_nonDisjointUnionEnvList_prop1)
apply (subgoal_tac " dom (snd (xs ! i)) ⊆ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply (rule dom_monotone,simp)
apply (subgoal_tac "xa ∈ dom (foldl op ⊗ empty (map snd xs))")
 prefer 2 apply blast
apply (rule nonDisjointUnionEnv_disjointUnionEnv_prop4,assumption)
by (simp add: disjointUnionEnv_def add: unionEnv_def)

text{*
Lemmas for nonDisjointUnionSafeEnv operator
*}

lemma empty_nonDisjointUnionSafeEnv :
  "empty ⊕ A = A"
by (simp add: nonDisjointUnionSafeEnv_def add: unionEnv_def)



text{*
Lemmas for triangle operator
*}

lemma safe_triangle:  
  "[| (def_pp Γ1 Γ2 L2); Γ2 x = Some s''|]  ==> (pp Γ1 Γ2 L2) x =  Some s''"
apply (simp add: pp_def add: def_pp_def add: safe_def add: unsafe_def)
apply (erule conjE)
apply (erule_tac x="x" in allE)+
apply auto
by (case_tac "y", simp+)

lemma safe_Gamma2_triangle: 
  "[|def_pp Γ1 Γ2 L2; Γ2 x = Some s''; x ∈ L2|] ==> Γ1 x = Some s'' ∨ x ∉ dom Γ1"
apply (simp add: def_pp_def)
apply (erule conjE)+
apply (erule_tac x="x" in allE)+
apply (simp add: unsafe_def,auto)
by (case_tac "y", simp_all)

lemma unsafe_triangle: 
  "[|def_pp Γ1 Γ2 L2; 
    def_disjointUnionEnv Γ2 (empty(x1 \<mapsto> m));
    L2 ⊆ dom (disjointUnionEnv Γ2  (empty(x1 \<mapsto> m)));
    x ≠ x1;
    Γ2 x ≠ Some s''; x ∈ L2|]  ==> (pp Γ1 Γ2 L2) x ≠  Some s''"
apply (simp add: def_pp_def)
apply (elim conjE)
apply (erule_tac x="x" in allE,clarsimp)+
apply (simp add: unsafe_def add: pp_def)
apply (split split_if_asm,clarsimp)
apply (simp add: safe_def)
apply (erule conjE)
apply (subgoal_tac "[| x ≠ x1; x ∈ L2; L2 ⊆ dom (Γ2 + [x1 \<mapsto> m])|]  ==> x ∈ dom Γ2",clarsimp)
apply (subgoal_tac "dom (disjointUnionEnv Γ2 [x1 \<mapsto> m]) = dom Γ2  ∪ dom [x1 \<mapsto> m]",simp)
 apply blast
by (rule union_dom_disjointUnionEnv,assumption)

lemma safe_Gamma_triangle_3: 
 "[|def_pp Γ1 Γ2 L2;  
   def_disjointUnionEnv Γ2 (empty(x1 \<mapsto> m));
   L2 ⊆ dom (disjointUnionEnv Γ2  (empty(x1 \<mapsto> m)));
   x ≠ x1;
   Γ2  x ≠  Some s''; 
   x∈ L2|] 
  ==> Γ1 x = Some s'' ∨ x ∉ dom Γ1"
apply (frule unsafe_triangle,assumption+)
apply (simp add: pp_def)
apply (split split_if_asm,clarsimp)
 apply (simp add: safe_def,clarsimp)
apply (simp add: safe_def add: def_pp_def)
apply (erule conjE)
apply (erule_tac x="x" in allE, simp)
apply (simp add: unsafe_def, clarsimp)
by (case_tac "y",simp_all)

lemma unsafe_Gamma2_triangle: 
  "[| def_pp  Γ1 Γ2 L2; (Γ2 + [x1 \<mapsto> m]) y ≠ Some s''; y ≠ x1 |] ==> Γ2 y ≠ Some  s''"
apply (simp add: disjointUnionEnv_def add: unionEnv_def)
apply (split split_if_asm)
 apply simp
apply (simp add: def_pp_def)
by auto

lemma condemned_Gamma2_triangle: 
  "[|def_pp  Γ1 Γ2 L2; (Γ2 + [x1 \<mapsto> s'']) x = Some d''|]  ==> (pp Γ1 Γ2 L2) x = Some d''"
apply (simp add: disjointUnionEnv_def add: unionEnv_def)
apply (split split_if_asm)
 apply (simp add: pp_def add: def_pp_def, clarsimp)
 apply (simp add: safe_def add: unsafe_def)
 apply (erule_tac x="x" in allE)+ apply (simp add: dom_def)
 apply (case_tac "ya", simp_all) 
apply (split split_if_asm)
 apply simp
by simp

lemma unsafe_triangle_unsafe_2: 
  "[| def_pp Γ1 Γ2 L2; (pp Γ1 Γ2 L2) x = Some d'' |] ==> Γ2 x ≠ Some s''"
apply (simp add: pp_def)
apply (split split_if_asm)
 apply (simp add: safe_def)
apply (simp add: safe_def)
apply (simp add: def_pp_def)
apply (simp add: unsafe_def)
by auto

lemma triangle_d_Gamma1_s_or_not_dom_Gamma1: 
  "[|def_disjointUnionEnv Γ2  (empty(x1 \<mapsto> m));
    L1 ⊆ dom Γ1; 
    L2 ⊆ dom (disjointUnionEnv Γ2  (empty(x1 \<mapsto> m))); 
    z ≠ x1;
    def_pp Γ1 Γ2 L2 ;(pp Γ1 Γ2 L2) z = Some d''; z ∈ L2 |]  
   ==> (Γ1 z = Some s'' ∨ z ∉ dom Γ1)"
apply (subgoal_tac "Γ2 z = Some d''");
 apply (subgoal_tac "z ∈ dom Γ2")
  prefer 2 apply blast
 apply (simp add: pp_def)
 apply (case_tac "z∈ L1")
  apply (rule disjI1)
  apply (subgoal_tac "z ∈ dom Γ1")
   prefer 2 apply blast
  apply (simp add: safe_def)
  apply (split split_if_asm, simp, simp)
  apply (simp add: def_pp_def)
  apply auto
  apply (erule_tac x="z" in allE)+
  apply simp
  apply (simp add: unsafe_def, auto)
 apply (simp add: safe_def)
 apply (split split_if_asm, simp)
  apply (simp add: def_pp_def, auto)
 apply (simp add: def_pp_def, auto)
 apply (simp add: unsafe_def, auto)
apply (simp add: def_pp_def)
apply (subgoal_tac "z ∈ dom Γ2")
 apply (erule conjE)
 apply (erule_tac x="z" in allE)+
 apply simp
 apply (simp add: unsafe_def add: pp_def)
 apply (split split_if_asm, simp, simp)
apply (subgoal_tac "dom (Γ2 + [x1 \<mapsto> m]) = dom Γ2 ∪ dom [x1 \<mapsto> m]") 
 prefer 2 apply (rule union_dom_disjointUnionEnv) apply simp
apply (subgoal_tac "dom [x1 \<mapsto> m] = {x1}",simp) 
 apply blast
by simp

lemma triangle_d_Gamma1_s_Gamma2_d: 
  "[|(pp Γ1 Γ2 L2) z = Some d'';  Γ1 z = Some s''|] ==> Γ2 z = Some d''"
apply (simp add: pp_def)
apply (split split_if_asm)
 apply simp
by simp

lemma triangle_prop: 
  "[|x ∈ dom Γ1; Γ1 x ≠ Some  s''|] 
   ==>  x ∈ dom (pp Γ1 Γ2 L2) ∧ (pp Γ1 Γ2 L2) x ≠ Some  s''"
by (simp add: pp_def, simp add: dom_def add: safe_def)

lemma triangle_d_Gamma1_d_or_Gamma2_d: 
  "[|(pp Γ1 Γ2 L2) z = Some d''|] ==> Γ1 z  = Some d'' ∨ Γ2 z = Some d''"
apply (simp add: pp_def add: safe_def)
apply (split split_if_asm)
 apply simp
by simp


lemma triangle_d_Gamma2_d_Gamma1_s: 
  "[|L1 ⊆ dom Γ1;
    def_pp Γ1 Γ2 L2; 
    (pp Γ1 Γ2 L2) z = Some d''; 
    Γ2 z = Some d''; z ∈ L1|] 
   ==> Γ1 z  = Some s'' ∧ z ∈ L2"
apply (subgoal_tac "z ∈ dom Γ1")
 prefer 2 apply (erule set_mp, assumption)
apply (rule conjI)
 apply (simp add: pp_def)
 apply (split split_if_asm)
  apply (simp_all add: safe_def)
 apply (simp add: def_pp_def)
 apply (erule conjE)
 apply (erule_tac x="z" in allE)+
 apply (simp add: unsafe_def)
 apply (erule conjE)
 apply (simp add: dom_def)
apply (simp add: def_pp_def)
apply (erule conjE)+
apply (erule_tac x="z" in allE,simp)+
by (simp add: unsafe_def add: pp_def add: safe_def,clarsimp)



lemma Gamma2_d_disjointUnionEnv_m_d: 
  "[|def_disjointUnionEnv  Γ2  (empty(x1 \<mapsto> m)); 
    Γ2 z = Some d''|]
   ==>  (disjointUnionEnv Γ2  (empty(x1 \<mapsto> m))) z = Some d''"
by (simp add: disjointUnionEnv_def unionEnv_def def_disjointUnionEnv_def, auto)


lemma dom_Gamma1_dom_triangle: 
  "x∈ dom Γ1 ==> x ∈  dom (pp Γ1 Γ2 L2)"
by (simp add: pp_def,auto)


lemma safe_triangle_safe_Gamma1: 
  "[| (pp Γ1 Γ2 L2) x = Some s'';  x ∈ dom Γ1 |] ==> Γ1 x = Some s''"
apply (simp add: pp_def)
apply (split split_if_asm)
 apply (simp add: safe_def)
by simp


lemma dom_Gamma2_dom_triangle: 
  "[| x ≠ x1; x ∈ dom (Γ2 + [x1 \<mapsto> m]) |]  ==> x ∈  dom (pp Γ1 Γ2 L2)"
apply (simp add: pp_def add: disjointUnionEnv_def add: unionEnv_def,clarsimp)
apply (split split_if_asm)
 apply (simp add: safe_def add: dom_def)
by simp

lemma usafe_Gamma2_unsafe_triangle: 
  "[|x≠x1;  
    x ∈ dom (Γ2 + [x1 \<mapsto> m]); 
    (Γ2 + [x1 \<mapsto> m]) x ≠ Some s''|]  
   ==> (pp Γ1 Γ2 L2) x ≠ Some s''"
apply (simp add: pp_def add: disjointUnionEnv_def add: unionEnv_def,clarsimp)
apply (split split_if_asm)
 apply (simp add: safe_def add: dom_def)
by simp


lemma def_disjointUnionEnv_monotone: 
  "def_disjointUnionEnv Γ2 [x1 \<mapsto> d''] ==> (Γ2 + [x1 \<mapsto> d'']) x1 = Some d''"
by (simp add: def_disjointUnionEnv_def add: disjointUnionEnv_def add: unionEnv_def)


lemma disjointUnionEnv_d_Gamma2_d: 
  "[|def_disjointUnionEnv Γ2 [x1 \<mapsto> d'']; 
    (Γ2 + [x1 \<mapsto> d'']) z = Some d''; 
    z≠ x1|]
   ==> Γ2 z = Some d''"
apply (simp add: disjointUnionEnv_def add: unionEnv_def)
apply (split split_if_asm,clarsimp)
by (simp add: def_disjointUnionEnv_def)


lemma Gamma2_d_disjointUnionEnv_d: 
  "[|def_disjointUnionEnv Γ2 [x1 \<mapsto> d'']; 
    Γ2 z = Some d''|]
  ==>  (Γ2 + [x1 \<mapsto> d'']) z = Some d''"
by (simp add: disjointUnionEnv_def unionEnv_def def_disjointUnionEnv_def, auto)


lemma dom_disjointUnionEnv_subset_dom_extend: 
  "[|def_disjointUnionEnv Γ2 [x1 \<mapsto> d'']; 
    dom (disjointUnionEnv Γ2 (empty(x1 \<mapsto> d''))) ⊆ dom (E1(x1 \<mapsto> v1)); 
   (Γ2 + [x1 \<mapsto> d'']) x = Some s''|]  
   ==> x ∈ dom E1"
apply (simp add: disjointUnionEnv_def add: unionEnv_def)
apply (subgoal_tac "x≠x1")
 apply blast
apply (simp add: def_disjointUnionEnv_def)
apply (split split_if_asm,clarsimp,simp)
by (split split_if_asm,clarsimp, simp)

lemma Gamma2_d_triangle_d: 
  "[|def_pp  Γ1 Γ2 L2; Γ2 x = Some d''|] ==> (pp Γ1 Γ2 L2) x = Some d''"
apply (simp add: pp_def add: def_pp_def, clarsimp)
 apply (simp add: safe_def add: unsafe_def)
 apply (erule_tac x="x" in allE)+ apply (simp add: dom_def)
apply (elim conjE)
 apply (case_tac "y", simp_all) 
done

lemma disjounitUnionEnv_d_triangle_d: 
  "[|x≠x1;def_pp  Γ1 Γ2 L2; (Γ2 + [x1 \<mapsto> d'']) x = Some d''|]  ==> (pp Γ1 Γ2 L2) x = Some d''"
apply (simp add: disjointUnionEnv_def add: unionEnv_def)
apply (split split_if_asm)
 apply (simp add: pp_def add: def_pp_def, clarsimp)
 apply (simp add: safe_def add: unsafe_def)
 apply (erule_tac x="x" in allE)+ apply (simp add: dom_def)
 apply (case_tac "ya", simp_all) 
done


(********** CASE **************)
(*declare dom_fun_upd [simp del]*)





end

Operators on type environments

lemma empty_unionEnv:

  unionEnv m empty = m

lemma dom_empty_unionEnv:

  dom (unionEnv m1.0 empty) = dom m1.0

lemma empty_disjointUnionEnv:

  m + empty = m

lemma dom_empty_disjointUnionEnv:

  dom (m1.0 + empty) = dom m1.0

lemma union_dom_disjointUnionEnv:

  def_disjointUnionEnv Γ1.0 Γ2.0 ==> dom (Γ1.0 + Γ2.0) = dom Γ1.0dom Γ2.0

lemma dom_disjointUnionEnv_monotone:

  dom (G + G') = dom Gdom G'

lemma empty_nonDisjointUnionEnv:

  emptyA = A

lemma refl_nonDisjointUnionEnv:

  AA = A

lemma list_induct3:

  [| P [] 0; !!x xs. P (x # xs) 0; !!i. P [] (Suc i);
     !!x xs i. P xs i ==> P (x # xs) (Suc i) |]
  ==> P xs i

lemma nonDisjointUnionEnv_conmutative:

  def_nonDisjointUnionEnv G G' ==> GG' = G'G

lemma nonDisjointUnionEnv_assoc:

  G1.0G2.0G3.0 = G1.0 ⊗ (G2.0G3.0)

lemma nonDisjointUnionEnv_disjointUnionEnv_assoc:

  (G1.0G2.0) + G3.0 = G1.0G2.0 + G3.0

lemma foldl_prop1:

  foldl op ⊗ (G'G) Gs = G' ⊗ foldl op ⊗ G Gs

lemma foldl_prop2:

  foldl op ⊗ (G'G) Gs + G'' = G' ⊗ foldl op ⊗ G Gs + G''

lemma union_dom_nonDisjointUnionEnv:

  dom (AB) = dom Adom B

lemma union_dom_nonDisjointUnionEnv_disjointUnionEnv:

  dom (AB + [x |-> m]) = dom Adom (B + [x |-> m])

lemma def_nonDisjointUnionEnvList_prop1:

  def_nonDisjointUnionEnvList (x # xs) -->
  def_nonDisjointUnionEnv x (foldl op ⊗ empty xs)

lemma dom_foldl_monotone:

  dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert)) =
  dom (snd a) ∪ dom (foldl op ⊗ empty (map snd assert))

lemma dom_foldl_disjointUnionEnv_monotone:

  dom (foldl op ⊗ (empty ⊗ snd a) (map snd assert) + [x |-> d'']) =
  dom (snd a) ∪ dom (foldl op ⊗ empty (map snd assert)) ∪ dom [x |-> d'']

lemma dom_monotone:

  i < length assert
  ==> dom (snd (assert ! i))  dom (foldl op ⊗ empty (map snd assert))

lemma dom_monotone_foldl_nonDijointUnionEnv:

  i < length assert
  ==> dom (snd (assert ! i))
       dom (foldl op ⊗ empty (map snd assert) + [x |-> d''])

lemma dom_Γi_subseteq_dom_Γ_case:

  0 < length assert
  ==> ∀i<length assert.
         dom (snd (assert ! i))  dom (foldl op ⊗ empty (map snd assert))

lemma dom_Γi_subseteq_dom_Γ_cased:

  0 < length assert
  ==> ∀i<length assert.
         dom (snd (assert ! i))
          dom (foldl op ⊗ empty (map snd assert) + [x |-> d''])

lemma nonDisjointUnionEnv_prop1:

  (GG') z = Some m ==> G z = Some mz  dom GG' z = Some m

lemma nonDisjointUnionEnv_prop2:

  [| def_nonDisjointUnionEnv G G'; (GG') z = Some m |]
  ==> G' z = Some mz  dom G'G z = Some m

lemma nonDisjointUnionEnv_prop5:

  [| xdom G; G x  Some m |] ==> (GG') x  Some m

lemma nonDisjointUnionEnv_prop6:

  [| def_nonDisjointUnionEnv G G'; zdom G'; G' z  Some m |]
  ==> (GG') z  Some m

lemma nonDisjointUnionEnv_prop6_1:

  [| xdom G; G x = Some m |] ==> (GG') x = Some m

lemma nonDisjointUnionEnv_prop6_2:

  [| def_nonDisjointUnionEnv G G'; G' z = Some m |] ==> (GG') z = Some m

lemma Otimes_prop1:

  i < length (map snd assert) -->
  0 < length (map snd assert) -->
  def_nonDisjointUnionEnvList (map snd assert) -->
  foldl op ⊗ empty (map snd assert) z = Some d'' -->
  zdom (snd (assert ! i)) --> snd (assert ! i) z = Some d''

lemma Otimes_prop2:

  [| i < length (map snd assert); 0 < length (map snd assert);
     def_nonDisjointUnionEnvList (map snd assert); xdom (snd (assert ! i));
     snd (assert ! i) x  Some s'' |]
  ==> foldl op ⊗ empty (map snd assert) x  Some s''

lemma Otimes_prop3:

  i < length (map snd assert) -->
  0 < length (map snd assert) -->
  def_nonDisjointUnionEnvList (map snd assert) -->
  snd (assert ! i) x = Some m --> foldl op ⊗ empty (map snd assert) x = Some m

lemma nonDisjointUnionEnv_disjointUnionEnv_prop1:

  [| xdom G; G x  Some m |] ==> ((GG') + G'') x  Some m

lemma nonDisjointUnionEnv_disjointUnionEnv_prop2:

  [| def_nonDisjointUnionEnv G G'; zdom G'; G' z  Some m |]
  ==> ((GG') + G'') z  Some m

lemma nonDisjointUnionEnv_disjointUnionEnv_prop3:

  [| xdom G; G x = Some m |] ==> ((GG') + G'') x = Some m

lemma nonDisjointUnionEnv_disjointUnionEnv_prop4:

  [| def_nonDisjointUnionEnv G G'; G' z = Some m |]
  ==> ((GG') + G'') z = Some m

lemma Otimes_prop2_not_s:

  [| i < length (map snd assert); 0 < length (map snd assert);
     def_nonDisjointUnionEnvList (map snd assert); ydom (snd (assert ! i));
     snd (assert ! i) y  Some s'' |]
  ==> (foldl op ⊗ empty (map snd assert) + [x |-> d'']) y  Some s''

lemma Otimes_prop4:

  [| i < length (map snd assert); 0 < length (map snd assert);
     def_nonDisjointUnionEnvList (map snd assert); snd (assert ! i) xa = Some m |]
  ==> (foldl op ⊗ empty (map snd assert) + [x |-> d'']) xa = Some m

lemma empty_nonDisjointUnionSafeEnv:

  emptyA = A

lemma safe_triangle:

  [| def_pp Γ1.0 Γ2.0 L2.0; Γ2.0 x = Some s'' |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x = Some s''

lemma safe_Gamma2_triangle:

  [| def_pp Γ1.0 Γ2.0 L2.0; Γ2.0 x = Some s''; xL2.0 |]
  ==> Γ1.0 x = Some s'' ∨ x  dom Γ1.0

lemma unsafe_triangle:

  [| def_pp Γ1.0 Γ2.0 L2.0; def_disjointUnionEnv Γ2.0 [x1.0 |-> m];
     L2.0  dom (Γ2.0 + [x1.0 |-> m]); x  x1.0; Γ2.0 x  Some s''; xL2.0 |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x  Some s''

lemma safe_Gamma_triangle_3:

  [| def_pp Γ1.0 Γ2.0 L2.0; def_disjointUnionEnv Γ2.0 [x1.0 |-> m];
     L2.0  dom (Γ2.0 + [x1.0 |-> m]); x  x1.0; Γ2.0 x  Some s''; xL2.0 |]
  ==> Γ1.0 x = Some s'' ∨ x  dom Γ1.0

lemma unsafe_Gamma2_triangle:

  [| def_pp Γ1.0 Γ2.0 L2.0; (Γ2.0 + [x1.0 |-> m]) y  Some s''; y  x1.0 |]
  ==> Γ2.0 y  Some s''

lemma condemned_Gamma2_triangle:

  [| def_pp Γ1.0 Γ2.0 L2.0; (Γ2.0 + [x1.0 |-> s'']) x = Some d'' |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x = Some d''

lemma unsafe_triangle_unsafe_2:

  [| def_pp Γ1.0 Γ2.0 L2.0; Γ1.0\<triangleright>Γ2.0 L2.0 x = Some d'' |]
  ==> Γ2.0 x  Some s''

lemma triangle_d_Gamma1_s_or_not_dom_Gamma1:

  [| def_disjointUnionEnv Γ2.0 [x1.0 |-> m]; L1.0  dom Γ1.0;
     L2.0  dom (Γ2.0 + [x1.0 |-> m]); z  x1.0; def_pp Γ1.0 Γ2.0 L2.0;
     Γ1.0\<triangleright>Γ2.0 L2.0 z = Some d''; zL2.0 |]
  ==> Γ1.0 z = Some s'' ∨ z  dom Γ1.0

lemma triangle_d_Gamma1_s_Gamma2_d:

  [| Γ1.0\<triangleright>Γ2.0 L2.0 z = Some d''; Γ1.0 z = Some s'' |]
  ==> Γ2.0 z = Some d''

lemma triangle_prop:

  [| xdom Γ1.0; Γ1.0 x  Some s'' |]
  ==> xdom Γ1.0\<triangleright>Γ2.0 L2.0Γ1.0\<triangleright>Γ2.0 L2.0 x  Some s''

lemma triangle_d_Gamma1_d_or_Gamma2_d:

  Γ1.0\<triangleright>Γ2.0 L2.0 z = Some d''
  ==> Γ1.0 z = Some d'' ∨ Γ2.0 z = Some d''

lemma triangle_d_Gamma2_d_Gamma1_s:

  [| L1.0  dom Γ1.0; def_pp Γ1.0 Γ2.0 L2.0;
     Γ1.0\<triangleright>Γ2.0 L2.0 z = Some d''; Γ2.0 z = Some d''; zL1.0 |]
  ==> Γ1.0 z = Some s'' ∧ zL2.0

lemma Gamma2_d_disjointUnionEnv_m_d:

  [| def_disjointUnionEnv Γ2.0 [x1.0 |-> m]; Γ2.0 z = Some d'' |]
  ==> (Γ2.0 + [x1.0 |-> m]) z = Some d''

lemma dom_Gamma1_dom_triangle:

  xdom Γ1.0 ==> xdom Γ1.0\<triangleright>Γ2.0 L2.0

lemma safe_triangle_safe_Gamma1:

  [| Γ1.0\<triangleright>Γ2.0 L2.0 x = Some s''; xdom Γ1.0 |]
  ==> Γ1.0 x = Some s''

lemma dom_Gamma2_dom_triangle:

  [| x  x1.0; xdom (Γ2.0 + [x1.0 |-> m]) |]
  ==> xdom Γ1.0\<triangleright>Γ2.0 L2.0

lemma usafe_Gamma2_unsafe_triangle:

  [| x  x1.0; xdom (Γ2.0 + [x1.0 |-> m]);
     (Γ2.0 + [x1.0 |-> m]) x  Some s'' |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x  Some s''

lemma def_disjointUnionEnv_monotone:

  def_disjointUnionEnv Γ2.0 [x1.0 |-> d'']
  ==> (Γ2.0 + [x1.0 |-> d'']) x1.0 = Some d''

lemma disjointUnionEnv_d_Gamma2_d:

  [| def_disjointUnionEnv Γ2.0 [x1.0 |-> d''];
     (Γ2.0 + [x1.0 |-> d'']) z = Some d''; z  x1.0 |]
  ==> Γ2.0 z = Some d''

lemma Gamma2_d_disjointUnionEnv_d:

  [| def_disjointUnionEnv Γ2.0 [x1.0 |-> d'']; Γ2.0 z = Some d'' |]
  ==> (Γ2.0 + [x1.0 |-> d'']) z = Some d''

lemma dom_disjointUnionEnv_subset_dom_extend:

  [| def_disjointUnionEnv Γ2.0 [x1.0 |-> d''];
     dom (Γ2.0 + [x1.0 |-> d''])  dom (E1.0(x1.0 |-> v1.0));
     (Γ2.0 + [x1.0 |-> d'']) x = Some s'' |]
  ==> xdom E1.0

lemma Gamma2_d_triangle_d:

  [| def_pp Γ1.0 Γ2.0 L2.0; Γ2.0 x = Some d'' |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x = Some d''

lemma disjounitUnionEnv_d_triangle_d:

  [| x  x1.0; def_pp Γ1.0 Γ2.0 L2.0; (Γ2.0 + [x1.0 |-> d'']) x = Some d'' |]
  ==> Γ1.0\<triangleright>Γ2.0 L2.0 x = Some d''