Theory StateModel
subsection ‹Extended Heaps›
text ‹In this file, we define extended heaps, which are triples of a permission heap, a shared action
guard state, and a family of unique action guard states. We also define a (partial) addition of two
extended heaps. Finally, we prove useful lemmas about them.›
theory StateModel
  imports FractionalHeap "HOL-Library.Multiset"
begin
type_synonym loc = nat
type_synonym val = nat
text ‹We store the initial value with the unique guard›
type_synonym f_heap = "(loc, val) fract_heap"
type_synonym 'a gs_heap = "(prat × 'a multiset) option"
type_synonym ('i, 'a) gu_heap = "'i ⇀ 'a list"
type_synonym ('i, 'a) heap = "f_heap × 'a gs_heap × ('i, 'a) gu_heap"
type_synonym  var   = string                
type_synonym  normal_heap  = "(nat ⇀ nat)"        
type_synonym  store = "(var ⇒ nat)"        
fun get_fh where "get_fh x = fst x"
fun get_gs where "get_gs x = fst (snd x)"
fun get_gu where "get_gu x = snd (snd x)"
text ‹Two "heaps" are compatible iff:
1. The fractional heaps have the same common values and sum to at most 1
2. The unique guard heaps are disjoint
3. The shared guards permissions sum to at most 1›
definition compatible :: "('i, 'a) heap ⇒ ('i, 'a) heap ⇒ bool" (infixl ‹##› 60) where
  "h ## h' ⟷ compatible_fract_heaps (get_fh h) (get_fh h') ∧ (∀k. get_gu h k = None ∨ get_gu h' k = None)
  ∧ (∀p p'. get_gs h = Some p ∧ get_gs h' = Some p' ⟶ pgte pwrite (padd (fst p) (fst p')))"
lemma compatibleI:
  assumes "compatible_fract_heaps (get_fh h) (get_fh h')"
      and "⋀k. get_gu h k = None ∨ get_gu h' k = None"
      and "⋀p p'. get_gs h = Some p ∧ get_gs h' = Some p' ⟹ pgte pwrite (padd (fst p) (fst p'))"
    shows "h ## h'"
  using assms(1) assms(2) assms(3) compatible_def by blast
fun add_gu_single where
  "add_gu_single None x = x"
| "add_gu_single x None = x"
definition add_gu where
  "add_gu u1 u2 k = add_gu_single (u1 k) (u2 k)"
lemma comp_add_gu_comm:
  assumes "⋀k. h k = None ∨ h' k = None"
  shows "add_gu h h' = add_gu h' h"
proof (rule ext)
  fix k show "add_gu h h' k = add_gu h' h k"
    by (metis add_gu_def add_gu_single.simps(1) add_gu_single.simps(2) assms not_None_eq)
qed
fun add_gs :: "(prat × 'a multiset) option ⇒ (prat × 'a multiset) option ⇒ (prat × 'a multiset) option"
  where
  "add_gs None x = x"
| "add_gs x None = x"
| "add_gs (Some p) (Some p') = Some (padd (fst p) (fst p'), snd p + snd p')"
text ‹Addition of shared guard states is cancellative.›
lemma add_gs_cancellative:
  assumes "add_gs a x = add_gs b x"
  shows "a = b"
  apply (cases x)
   apply (metis add_gs.elims assms not_None_eq)
  apply (cases a)
  apply (cases b)
  apply simp
   apply (metis add_gs.simps(1) add_gs.simps(3) assms fst_conv not_pgte_charact option.sel padd_comm pgt_implies_pgte sum_larger)
  apply (cases b)
  apply (metis add_gs.simps(1) add_gs.simps(3) assms fst_conv not_pgte_charact option.sel padd_comm pgt_implies_pgte sum_larger)
proof -
  fix xx aa bb assume "x = Some xx" "a = Some aa" "b = Some bb"
  then have "fst aa = fst bb"
    using assms padd_cancellative[of "padd (fst aa) (fst xx)"]
     Pair_inject add_gs.simps(3) option.inject by auto
  moreover have "snd aa = snd bb"
    using add_left_cancel[of "snd xx" "snd aa" "snd bb"]
    using ‹a = Some aa› ‹b = Some bb› ‹x = Some xx› assms by auto
  ultimately show "a = b"
    by (simp add: ‹a = Some aa› ‹b = Some bb› prod_eq_iff)
qed
text ‹Addition of shared guard states is commutative.›
lemma add_gs_comm:
  "add_gs a b = add_gs b a"
proof (cases a)
  case None
  then show ?thesis
    by (metis add_gs.elims add_gs.simps(1) add_gs.simps(2))
next
  case (Some aa)
  then have "a = Some aa" by simp
  then show ?thesis
  proof (cases b)
    case None
    then show ?thesis
      using Some by force
  next
    case (Some bb)
    moreover have "padd (fst aa) (fst bb) = padd (fst bb) (fst aa) ∧ snd aa + snd bb = snd bb + snd aa"
      using padd_comm by force
    ultimately show ?thesis
      using ‹a = Some aa› by force
  qed
qed
lemma compatible_fheaps_comm:
  assumes "compatible_fract_heaps a b"
  shows "add_fh a b = add_fh b a"
proof (rule ext)
  fix x show "add_fh a b x = add_fh b a x"
  proof (cases "a x")
    case None
    then show ?thesis
      by (metis add_fh_def add_fh_def fadd_options.simps(1) fadd_options.simps(2) option.exhaust_sel)
  next
    case (Some aa)
    then have "a x = Some aa" by simp
    then show ?thesis
    proof (cases "b x")
      case None
      then show ?thesis
        by (simp add: Some add_fh_def)
    next
      case (Some bb)
      then show ?thesis
        using ‹a x = Some aa› add_fh_def[of a b] add_fh_def[of b a] assms compatible_fract_heapsE(2) fadd_options.simps(3) padd_comm
        by (metis (full_types))
    qed
  qed
qed
text ‹The following function defines addition between two extended heaps.›
fun plus :: "('i, 'a) heap option ⇒ ('i, 'a) heap option ⇒ ('i, 'a) heap option" (infixl ‹⊕› 63) where
  "None ⊕ _ = None"
| "_ ⊕ None = None"
| "Some h1 ⊕ Some h2 = (if h1 ## h2 then Some (add_fh (get_fh h1) (get_fh h2), add_gs (get_gs h1) (get_gs h2), add_gu (get_gu h1) (get_gu h2)) else None)"
lemma :
  assumes "Some x = Some a ⊕ Some b"
  shows "get_fh x = add_fh (get_fh a) (get_fh b)"
    and "get_gs x = add_gs (get_gs a) (get_gs b)"
    and "get_gu x = add_gu (get_gu a) (get_gu b)"
    apply (metis assms eq_fst_iff get_fh.simps option.inject option.simps(3) plus.simps(3))
   apply (metis assms fst_eqD get_gs.simps option.distinct(1) option.inject plus.simps(3) snd_conv)
  by (metis assms get_gu.elims option.distinct(1) option.sel plus.simps(3) snd_conv)
lemma compatible_eq:
  "Some a ⊕ Some b = None ⟷ ¬ a ## b"
  by simp
lemma compatible_comm:
  "a ## b ⟷ b ## a"
proof -
  have "⋀a b. a ## b ⟹ b ## a"
  proof -
    fix a b assume asm0: "a ## b"
    show "b ## a"
    proof (rule compatibleI)
      show "compatible_fract_heaps (get_fh b) (get_fh a)"
        using asm0 compatible_def compatible_fract_heaps_comm by blast
      show "⋀k. get_gu b k = None ∨ get_gu a k = None"
        by (meson asm0 compatible_def)
      show "⋀p p'. get_gs b = Some p ∧ get_gs a = Some p' ⟹ pgte pwrite (padd (fst p) (fst p'))"
        by (metis asm0 compatible_def padd_comm)
    qed
  qed
  then show ?thesis
    by blast
qed
lemma heap_ext:
  assumes "get_fh a = get_fh b"
      and "get_gs a = get_gs b"
      and "get_gu a = get_gu b"
    shows "a = b"
  by (metis assms(1) assms(2) assms(3) get_fh.simps get_gs.simps get_gu.elims prod.expand)
text ‹Addition of two extended heaps is commutative.›
lemma plus_comm:
  "a ⊕ b = b ⊕ a"
proof -
  have r: "⋀x a b. Some x = Some a ⊕ Some b ⟹ Some x = Some b ⊕ Some a"
  proof -
    fix x a b assume asm0: "Some x = Some a ⊕ Some b"
    then obtain y where "Some y = Some b ⊕ Some a"
      by (metis compatible_comm plus.simps(3))
    have "x = y"
    proof (rule heap_ext)
      show "get_fh x = get_fh y"
        by (metis ‹Some y = Some b ⊕ Some a› asm0 compatible_def compatible_eq compatible_fheaps_comm plus_extract(1))
      show "get_gs x = get_gs y"
        by (metis ‹Some y = Some b ⊕ Some a› add_gs_comm asm0 plus_extract(2))
      show "get_gu x = get_gu y" using comp_add_gu_comm[of "get_gu x" "get_gu y"]
        by (metis ‹Some y = Some b ⊕ Some a› asm0 comp_add_gu_comm compatible_def compatible_eq plus_extract(3))
    qed
    then show "Some x = Some b ⊕ Some a"
      by (simp add: ‹Some y = Some b ⊕ Some a›)
  qed
  then show ?thesis
  proof (cases "a ⊕ b")
    case None
    then show ?thesis
      by (metis (no_types, opaque_lifting) compatible_comm compatible_eq plus.elims)
  next
    case (Some ab)
    then have "a = Some (the a) ∧ b = Some (the b)"
      by (metis option.collapse option.distinct(1) plus.simps(1) plus.simps(2))
    then show ?thesis
      by (metis ‹⋀x b a. Some x = Some a ⊕ Some b ⟹ Some x = Some b ⊕ Some a› plus.elims)
  qed
qed
lemma asso2:
  assumes "Some a ⊕ Some b = Some ab"
      and "¬ b ## c"
    shows "¬ ab ## c"
proof (cases "compatible_fract_heaps (get_fh b) (get_fh c)")
  case True
  then have r: "(∃k. get_gu b k ≠ None ∧ get_gu c k ≠ None)
  ∨ (∃p p'. get_gs b = Some p ∧ get_gs c = Some p' ∧ pgt (padd (fst p) (fst p')) pwrite)"
    by (metis assms(2) compatible_def not_pgte_charact)
  then show ?thesis
  proof (cases "∃k. get_gu b k ≠ None ∧ get_gu c k ≠ None")
    case True
    then obtain k where "get_gu b k ≠ None ∧ get_gu c k ≠ None"
      by auto
    then have "get_gu ab k ≠ None"
      using add_gu_def[of "get_gu a" "get_gu b"] add_gu_single.simps(1) assms(1) compatible_def compatible_eq option.distinct(1) plus_extract(3)
      by metis
    then show ?thesis
      by (meson ‹get_gu b k ≠ None ∧ get_gu c k ≠ None› compatible_def)
  next
    case False
    then obtain p p' where "get_gs b = Some p ∧ get_gs c = Some p' ∧ pgt (padd (fst p) (fst p')) pwrite"
      using r by blast
    moreover have "get_gs ab = add_gs (get_gs a) (Some p)"
      by (metis assms(1) calculation plus_extract(2))
    then show ?thesis
    proof (cases "get_gs a")
      case None
      then show ?thesis
        by (metis ‹get_gs ab = add_gs (get_gs a) (Some p)› add_gs.simps(1) calculation compatible_def not_pgte_charact)
    next
      case (Some pa)
      then have "get_gs ab = Some (padd (fst pa) (fst p), snd pa + snd p)"
        using ‹get_gs ab = add_gs (get_gs a) (Some p)› by auto
      then have "pgte (padd (fst pa) (fst p)) (fst p)"
        using padd_comm pgt_implies_pgte sum_larger by presburger
      then have "pgt (padd (padd (fst pa) (fst p)) (fst p')) pwrite"
        using calculation padd.rep_eq pgt.rep_eq pgte.rep_eq by auto
      then show ?thesis
        by (metis ‹get_gs ab = Some (padd (fst pa) (fst p), snd pa + snd p)› calculation compatible_def fst_conv not_pgte_charact)
    qed
  qed
next
  case False
  then show ?thesis
  proof (cases "compatible_fractions (get_fh b) (get_fh c)")
    case True
    then have "¬ same_values (get_fh b) (get_fh c)"
      using False compatible_fract_heaps_def by blast
    then obtain l pb pc where "get_fh b l = Some pb" "get_fh c l = Some pc" "snd pc ≠ snd pb"
      using same_values_def by fastforce
    then obtain pab where "get_fh ab l = Some pab" "snd pab = snd pb"
      apply (cases "get_fh a l")
       apply (metis (no_types, lifting) add_fh_def assms(1) fadd_options.simps(2) plus_comm plus_extract(1))
      using add_fh_def[of "get_fh b" "get_fh a" l] assms(1) fadd_options.simps(3) plus_comm plus_extract(1) snd_conv
      by metis
    then show ?thesis
      by (metis ‹get_fh c l = Some pc› ‹snd pc ≠ snd pb› compatible_def compatible_fract_heapsE(2))
  next
    case False
    then obtain pb pc l where "get_fh b l = Some pb" "get_fh c l = Some pc" "pgt (padd (fst pb) (fst pc)) pwrite"
      using compatible_fractions_def not_pgte_charact by blast
    then show ?thesis
    proof (cases "get_fh a l")
      case None
      then have "get_fh ab l = Some pb"
        by (metis (no_types, lifting) ‹get_fh b l = Some pb› add_fh_def assms(1) fadd_options.simps(1) plus_extract(1))
      then show ?thesis
        by (meson ‹get_fh c l = Some pc› ‹pgt (padd (fst pb) (fst pc)) pwrite› compatible_def compatible_fract_heaps_def compatible_fractions_def not_pgte_charact)
    next
      case (Some pa)
      then obtain pab where "get_fh ab l = Some pab" "fst pab = padd (fst pa) (fst pb)"
        by (metis (mono_tags, opaque_lifting) ‹get_fh b l = Some pb› add_fh_def assms(1) fadd_options.simps(3) fst_conv plus_extract(1))
      then have "pgte (fst pab) (fst pb)"
        by (metis padd_comm pgt_implies_pgte sum_larger)
      then have "pgt (padd (fst pab) (fst pc)) pwrite"
        using ‹pgt (padd (fst pb) (fst pc)) pwrite› padd.rep_eq pgt.rep_eq pgte.rep_eq by force
      then show ?thesis
        by (meson ‹get_fh ab l = Some pab› ‹get_fh c l = Some pc› compatible_def compatible_fract_heapsE(1) not_pgte_charact)
    qed
  qed
qed
lemma :
  assumes "Some x = Some a ⊕ Some b"
      and "get_fh a l = Some pa"
      and "get_fh b l = Some pb"
    shows "snd pa = snd pb ∧ pgte pwrite (padd (fst pa) (fst pb)) ∧ get_fh x l = Some (padd (fst pa) (fst pb), snd pa)"
  using add_fh_def[of "get_fh a" "get_fh b"] assms(1) assms(2) assms(3) compatible_def[of a b] compatible_eq
    compatible_fract_heapsE(1)[of "get_fh a" "get_fh b"] compatible_fract_heapsE(2)[of "get_fh a" "get_fh b"]
    fadd_options.simps(3)[of pa pb] option.distinct(1) plus_extract(1)[of x a b]
  by metis
lemma asso1:
  assumes "Some a ⊕ Some b = Some ab"
      and "Some b ⊕ Some c = Some bc"
    shows "Some ab ⊕ Some c = Some a ⊕ Some bc"
proof (cases "Some ab ⊕ Some c")
  case None
  then show ?thesis
  proof (cases "compatible_fract_heaps (get_fh ab) (get_fh c)")
    case True
    then have r: "(∃k. get_gu ab k ≠ None ∧ get_gu c k ≠ None) ∨ (∃p p'. get_gs ab = Some p ∧ get_gs c = Some p'
      ∧ pgt (padd (fst p) (fst p')) pwrite)"
      by (metis None compatible_def compatible_eq not_pgte_charact)
    then show ?thesis
    proof (cases "∃k. get_gu ab k ≠ None ∧ get_gu c k ≠ None")
      case True
      then obtain k where "get_gu ab k ≠ None ∧ get_gu c k ≠ None"
        by presburger
      then have "get_gu a k ≠ None ∨ get_gu b k ≠ None"
        by (metis (no_types, lifting) add_gu_def add_gu_single.simps(1) assms(1) plus_extract(3))
      then show ?thesis
        by (metis ‹get_gu ab k ≠ None ∧ get_gu c k ≠ None› assms(2) asso2 compatible_def compatible_eq option.discI plus_comm)
    next
      case False
      then obtain pab pc where "get_gs ab = Some pab ∧ get_gs c = Some pc
      ∧ pgt (padd (fst pab) (fst pc)) pwrite"
        using r by blast
      then show ?thesis
        apply (cases "get_gs a")
         apply (metis add_gs.simps(1) assms(1) assms(2) compatible_def compatible_eq not_pgte_charact option.discI plus_extract(2))
        apply (cases "get_gs b")
         apply (metis add_gs.simps(1) add_gs.simps(2) assms(1) assms(2) compatible_def compatible_eq not_pgte_charact plus_extract(2))
      proof -
        fix pa pb assume asm: "get_gs ab = Some pab ∧ get_gs c = Some pc ∧ pgt (padd (fst pab) (fst pc)) pwrite"
        "get_gs a = Some pa" "get_gs b = Some pb"
        then have "pab = (padd (fst pa) (fst pb), snd pa + snd pb)"
          by (metis add_gs.simps(3) assms(1) option.sel plus_extract(2))
        then show "Some ab ⊕ Some c = Some a ⊕ Some bc"
          using None ‹get_gs a = Some pa› asm
            ‹get_gs b = Some pb› add_gs.simps(3) assms(2) compatible_def[of a bc]
            compatible_eq fst_conv not_pgte_charact[of pwrite "padd (fst pab) (fst pc)"] padd_asso plus_extract(2)
          by metis
      qed
    qed
  next
    case False
    then show ?thesis
    proof (cases "compatible_fractions (get_fh ab) (get_fh c)")
      case True
      then have "¬same_values (get_fh ab) (get_fh c)"
        using False compatible_fract_heaps_def
        by blast
      then obtain l pab pc where "get_fh ab l = Some pab" "get_fh c l = Some pc" "snd pab ≠ snd pc"
        using same_values_def by blast
        
      then show ?thesis
        apply (cases "get_fh a l")
        
         apply (metis (no_types, lifting) add_fh_def assms(1) assms(2) compatible_def compatible_eq compatible_fract_heapsE(2) fadd_options.simps(1) option.distinct(1) plus_extract(1))
      proof -
        fix pa assume "get_fh ab l = Some pab" "get_fh c l = Some pc" "snd pab ≠ snd pc" "get_fh a l = Some pa"
        moreover have "same_values (get_fh a) (get_fh b)"
          by (metis assms(1) compatible_def compatible_fract_heaps_def option.discI plus.simps(3))
        ultimately have "snd pa = snd pab"
          apply (cases "get_fh b l")
           apply (metis (no_types, lifting) add_fh_def assms(1) fadd_options.simps(2) option.inject plus_extract(1))
          by (metis (no_types, lifting) add_fh_def assms(1) fadd_options.simps(3) option.sel plus_extract(1) snd_eqD)
        then show ?thesis
          by (metis (full_types) None ‹get_fh a l = Some pa› ‹get_fh c l = Some pc› ‹snd pab ≠ snd pc› assms(2) asso2 compatible_def compatible_eq compatible_fract_heapsE(2) plus_comm)
      qed
    next
      case False
      then obtain l pab pc where "get_fh ab l = Some pab" "get_fh c l = Some pc" "pgt (padd (fst pab) (fst pc)) pwrite"
        using compatible_fractions_def not_pgte_charact by blast
      then show ?thesis
      proof (cases "get_fh a l")
        case None
        then have "get_fh b l = Some pab"
          by (metis (no_types, lifting) ‹get_fh ab l = Some pab› add_fh_def assms(1) fadd_options.simps(1) plus_extract(1))
        then show ?thesis
          by (metis ‹get_fh c l = Some pc› ‹pgt (padd (fst pab) (fst pc)) pwrite› assms(2) compatible_def compatible_fract_heapsE(1) not_pgte_charact option.simps(3) plus.simps(3))
      next
        case (Some pa)
        then have "get_fh a l = Some pa" by simp
        then show ?thesis
        proof (cases "get_fh b l")
          case None
          then have "pa = pab"
            by (metis (no_types, lifting) Some ‹get_fh ab l = Some pab› add_fh_def assms(1) fadd_options.simps(2) option.inject plus_extract(1))
          then show ?thesis
            by (metis Some ‹get_fh ab l = Some pab› ‹get_fh c l = Some pc› ‹pgt (padd (fst pab) (fst pc)) pwrite› assms(2) asso2 compatible_def compatible_fract_heapsE(1) not_pgte_charact padd_comm plus.simps(3) plus_comm)
        next
          case (Some pb)
          then have "fst pab = padd (fst pa) (fst pb)"
            using ‹get_fh a l = Some pa› ‹get_fh ab l = Some pab› add_fh_def[of "get_fh a" "get_fh b"] assms(1) compatible_def compatible_eq
                compatible_fract_heapsE(2)[of "get_fh a" "get_fh b"] fadd_options.simps(3)
                fst_apfst option.discI option.sel plus_extract(1)[of ab a b] prod.collapse snd_apfst
            by force
          then have "pgt (padd (fst pa) (padd (fst pb) (fst pc))) pwrite"
            using ‹pgt (padd (fst pab) (fst pc)) pwrite› padd_asso by auto
          moreover obtain pbc where "get_fh bc l = Some pbc" "fst pbc = padd (fst pb) (fst pc)"
            by (metis (no_types, opaque_lifting) Some ‹get_fh c l = Some pc› add_fh_def assms(2) fadd_options.simps(3) fst_conv plus_extract(1))
          ultimately show ?thesis
            by (metis None ‹get_fh a l = Some pa› compatible_def compatible_eq compatible_fract_heapsE(1) not_pgte_charact)
        qed
      qed
    qed
  qed
next
  case (Some x)
  then have "Some ab ⊕ Some c = Some x" by simp
  have "a ## bc"
  proof (rule compatibleI)
    show "compatible_fract_heaps (get_fh a) (get_fh bc)"
    proof (rule compatible_fract_heapsI)
      fix l pa pbc assume asm0: "get_fh a l = Some pa ∧ get_fh bc l = Some pbc"
      have "pgte pwrite (padd (fst pa) (fst pbc)) ∧ snd pa = snd pbc"
      proof (cases "get_fh c l")
        case None
        then have "get_fh b l = Some pbc"
          by (metis (no_types, lifting) add_fh_def asm0 assms(2) fadd_options.elims option.discI plus_extract(1))
        then show ?thesis
          by (metis (no_types, lifting) asm0 assms(1) compatible_def compatible_eq compatible_fract_heapsE(1) compatible_fract_heapsE(2) option.discI)
      next
        case (Some pc)
        then have "get_fh c l = Some pc" by simp
        then show ?thesis
        proof (cases "get_fh b l")
          case None
          then have "get_fh ab l = Some pa"
            by (metis (no_types, lifting) add_fh_def asm0 assms(1) fadd_options.simps(2) plus_extract(1))
          moreover have "pbc = pc"
            by (metis (no_types, lifting) None Some add_fh_def asm0 assms(2) fadd_options.simps(2) option.inject plus_comm plus_extract(1))
          ultimately show ?thesis
            by (metis (no_types, lifting) Some ‹Some ab ⊕ Some c = Some x› compatible_def compatible_eq compatible_fract_heapsE(1) compatible_fract_heapsE(2) option.discI)
        next
          case (Some pb)
          then obtain pab where "get_fh ab l = Some pab" "fst pab = padd (fst pa) (fst pb)" "snd pab = snd pa" 
            by (metis (mono_tags, opaque_lifting) add_fh_def asm0 assms(1) fadd_options.simps(3) fst_conv plus_extract(1) snd_conv)
          then have "pgte pwrite (padd (padd (fst pa) (fst pb)) (fst pc))"
            by (metis ‹Some ab ⊕ Some c = Some x› ‹get_fh c l = Some pc› compatible_def compatible_eq compatible_fract_heapsE(1) option.distinct(1))
          then have "pgte pwrite (padd (fst pa) (fst pbc))"
            by (metis (no_types, lifting) Some ‹get_fh c l = Some pc› add_fh_def asm0 assms(2) fadd_options.simps(3) fst_conv option.sel padd_asso plus_extract(1))
          moreover have "snd pa = snd pb"
            by (metis Some asm0 assms(1) compatible_def compatible_fract_heapsE(2) option.simps(3) plus.simps(3))
          then have "snd pa = snd pbc"
            by (metis (no_types, opaque_lifting) Some ‹get_fh c l = Some pc› add_fh_def asm0 assms(2) fadd_options.simps(3) option.sel plus_extract(1) snd_conv)
          ultimately show ?thesis by blast
        qed
      qed
      then show "pgte pwrite (padd (fst pa) (fst pbc))"
        by auto
      show "snd pa = snd pbc"
        by (simp add: ‹pgte pwrite (padd (fst pa) (fst pbc)) ∧ snd pa = snd pbc›)
    qed
    show "⋀k. get_gu a k = None ∨ get_gu bc k = None"
    proof -
      fix k show "get_gu a k = None ∨ get_gu bc k = None"     
      proof (cases "get_gu a k")
        case (Some aa)
        then have "get_gu b k = None ∨ get_gu c k = None"
          by (metis assms(2) compatible_def compatible_eq option.discI)
        then show ?thesis
          using Some ‹Some ab ⊕ Some c = Some x› add_gu_def[of "get_gu a" "get_gu b"]
            add_gu_def[of "get_gu b" "get_gu c"] add_gu_single.simps(1) add_gu_single.simps(2)
            assms(1) assms(2) compatible_def compatible_eq option.distinct(1) plus_extract(3)
          by metis
      qed (simp)
    qed
    fix pa pbc assume "get_gs a = Some pa ∧ get_gs bc = Some pbc"
    show "pgte pwrite (padd (fst pa) (fst pbc)) "
    proof (cases "get_gs b")
      case None
      then show ?thesis by (metis Some ‹get_gs a = Some pa ∧ get_gs bc = Some pbc› add_gs.simps(1) add_gs.simps(2) assms(1) assms(2) compatible_def compatible_eq option.discI plus_extract(2))
    next
      case (Some pb)
      then have "get_gs b = Some pb" by simp
      then show ?thesis
      proof (cases "get_gs c")
        case None
        then show ?thesis
          by (metis Some ‹get_gs a = Some pa ∧ get_gs bc = Some pbc› add_gs.simps(2) assms(1) assms(2) compatible_def compatible_eq option.distinct(1) plus_extract(2))
      next
        case (Some pc)
        then have "padd (fst pa) (fst pbc) = padd (fst pa) (padd (fst pb) (fst pc))"
          by (metis (no_types, lifting) ‹get_gs a = Some pa ∧ get_gs bc = Some pbc› ‹get_gs b = Some pb› add_gs.simps(3) assms(2) fst_conv option.sel plus_extract(2))
        also have "... = padd (padd (fst pa) (fst pb)) (fst pc)"
          using padd_asso by force
        moreover obtain pab where "get_gs ab = Some pab"
          by (metis ‹get_gs a = Some pa ∧ get_gs bc = Some pbc› ‹get_gs b = Some pb› add_gs.simps(3) assms(1) plus_extract(2))
        then have "pgte pwrite (padd (fst pab) (fst pc))"
          by (metis Some ‹Some ab ⊕ Some c = Some x› compatible_def compatible_eq option.simps(3))
        ultimately show ?thesis
          by (metis (no_types, lifting) ‹get_gs a = Some pa ∧ get_gs bc = Some pbc› ‹get_gs ab = Some pab› ‹get_gs b = Some pb› add_gs.simps(3) assms(1) fst_conv option.sel plus_extract(2))
      qed
    qed
  qed
  then obtain y where "Some y = Some a ⊕ Some bc"
    by simp
  moreover have "x = y"
  proof (rule heap_ext)
    show "get_gu x = get_gu y"
    proof (rule ext)
      fix k show "get_gu x k = get_gu y k"
        apply (cases "get_gu a k")
        using Some add_gu_def[of "get_gu a"] add_gu_def[of "get_gu b"] add_gu_def[of "get_gu ab"]
          add_gu_single.simps(1) assms(1) assms(2) calculation
          plus_extract(3)[of ab a b] plus_extract(3)[of bc b c] plus_extract(3)[of y a bc] plus_extract(3)[of x ab c]
        apply simp
        apply (cases "get_gu b k")
        using Some add_gu_def[of "get_gu a"] add_gu_def[of "get_gu b"] add_gu_def[of "get_gu ab"]
          add_gu_single.simps(1) assms(1) assms(2) calculation
          plus_extract(3)[of ab a b] plus_extract(3)[of bc b c] plus_extract(3)[of y a bc] plus_extract(3)[of x ab c]
            add_gu_single.simps(1) add_gu_single.simps(2) assms(1) assms(2) calculation
        apply simp
        by (metis assms(1) compatible_def compatible_eq option.simps(3))
    qed
    show "get_gs x = get_gs y"
      apply (cases "get_gs a")
       apply (metis (mono_tags, lifting) Some add_gs.simps(1) assms(1) assms(2) calculation plus_extract(2))
      apply (cases "get_gs b")
       apply (metis (mono_tags, lifting) Some add_gs.simps(1) add_gs.simps(2) assms(1) assms(2) calculation plus_extract(2))
      apply (cases "get_gs c")
       apply (metis Some add_gs.simps(1) assms(1) assms(2) calculation plus_comm plus_extract(2))
    proof -
      fix ga gb gc assume asm0: "get_gs a = Some ga" "get_gs b = Some gb" "get_gs c = Some gc"
      then obtain gab gbc where r: "get_gs ab = Some gab" "get_gs bc = gbc"
        by (metis add_gs.simps(3) assms(1) plus_extract(2))
      then have "get_gs x = Some (padd (padd (fst ga) (fst gb)) (fst gc), (snd ga + snd gb) + snd gc)"
        by (metis (no_types, lifting) Some add_gs.simps(3) asm0(1) asm0(2) asm0(3) assms(1) fst_conv plus_extract(2) snd_conv)
      moreover have "get_gs y = Some (padd (fst ga) (padd (fst gb) (fst gc)), snd ga + (snd gb + snd gc))"
        by (metis (mono_tags, opaque_lifting) ‹Some y = Some a ⊕ Some bc› add_gs.simps(3) asm0(1) asm0(2) asm0(3) assms(2) fst_conv plus_extract(2) prod.exhaust_sel snd_conv)
      ultimately show "get_gs x = get_gs y"
        by (simp add: padd_asso)
    qed
    show "get_fh x = get_fh y"
      by (metis Some add_fh_asso assms(1) assms(2) calculation plus_extract(1))
  qed
  ultimately show ?thesis using Some by presburger
qed
lemma simpler_asso:
  "(Some a ⊕ Some b) ⊕ Some c = Some a ⊕ (Some b ⊕ Some c)"
proof (cases "Some a ⊕ Some b")
  case None
  then show ?thesis
    by (metis (no_types, opaque_lifting) asso2 compatible_eq option.exhaust plus.simps(1) plus_comm)
next
  case (Some ab)
  then have ab: "Some ab = Some a ⊕ Some b" by simp
  then show ?thesis
  proof (cases "Some b ⊕ Some c")
    case None
    then show ?thesis
      by (metis Some asso2 compatible_eq plus.simps(2))
  next
    case (Some bc)
    then show ?thesis
      by (metis ab asso1)
  qed
qed
text ‹Addition of two extended heaps is associative.›
lemma plus_asso:
  "(a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)"
proof (cases a)
  case (Some aa)
  then have aa: "a = Some aa" by simp
  then show ?thesis
  proof (cases b)
    case (Some bb)
    then have bb: "b = Some bb" by simp
    then show ?thesis
    proof (cases c)
      case None
      then show ?thesis
        by (simp add: plus_comm)
    next
      case (Some cc)
      then show ?thesis
        using aa bb simpler_asso by blast
    qed
  qed (simp)
qed (simp)
text ‹We define the extension order between extended heaps.›
definition larger :: "('i, 'a) heap ⇒ ('i, 'a) heap ⇒ bool" (infixl ‹≽› 55) where
  "a ≽ b ⟷ (∃c. Some a = Some b ⊕ Some c)"
text ‹The extension order between extended heaps is transitive.›
lemma larger_trans:
  assumes "a ≽ b"
      and "b ≽ c"
    shows "a ≽ c"
proof -
  obtain r1 where "Some a = Some b ⊕ Some r1"
    using assms(1) larger_def by blast
  moreover obtain r2 where "Some b = Some c ⊕ Some r2"
    using assms(2) larger_def by blast
  moreover obtain r where "Some r = Some r1 ⊕ Some r2"
    by (metis (no_types, opaque_lifting) calculation(1) calculation(2) not_Some_eq plus.simps(1) plus_asso plus_comm)
  ultimately show ?thesis
    by (metis larger_def plus_comm simpler_asso)
qed
lemma comp_smaller:
  assumes "a ## b"
      and "Some b = Some c ⊕ Some d"
    shows "a ## c"
  by (metis assms(1) assms(2) option.distinct(1) plus.simps(1) plus.simps(3) plus_asso)
lemma full_sguard_sum_same:
  assumes "get_gs a = Some (pwrite, sargs)"
      and "Some h = Some a ⊕ Some b"
    shows "get_gs h = Some (pwrite, sargs)"
proof (cases "get_gs b")
  case None
  then show ?thesis
    by (metis add_gs.simps(2) assms(1) assms(2) fst_conv get_gs.elims option.sel option.simps(3) plus.simps(3) snd_eqD)
next
  case (Some a)
  then show ?thesis
    by (metis assms(1) assms(2) compatible_def compatible_eq fst_eqD not_pgte_charact option.simps(3) sum_larger)
qed
lemma full_uguard_sum_same:
  assumes "get_gu a k = Some uargs"
      and "Some h = Some a ⊕ Some b"
    shows "get_gu h k = Some uargs"
proof (cases "get_gu b k")
  case None
  then show ?thesis
    by (metis (no_types, lifting) add_gu_def add_gu_single.simps(2) assms(1) assms(2) plus_extract(3))
next
  case (Some a)
  then show ?thesis
    by (metis assms(1) assms(2) compatible_def compatible_eq option.simps(3))
qed
lemma smaller_more_compatible:
  assumes "a ## b"
      and "a ≽ c"
    shows "c ## b"
  by (meson assms(1) assms(2) comp_smaller compatible_comm larger_def)
lemma equiv_sum_get_fh:
  assumes "get_fh a = get_fh a'"
      and "get_fh b = get_fh b'"
      and "Some x = Some a ⊕ Some b"
      and "Some x' = Some a' ⊕ Some b'"
    shows "get_fh x = get_fh x'"
  by (metis assms(1) assms(2) assms(3) assms(4) fst_eqD get_fh.elims option.discI option.sel plus.simps(3))
lemma addition_cancellative:
  assumes "Some a = Some b ⊕ Some c"
      and "Some a = Some b' ⊕ Some c"
    shows "b = b'"
proof (rule heap_ext)
  show "get_gu b = get_gu b'"
  proof (rule ext)
    fix k show "get_gu b k = get_gu b' k"
    apply (cases "get_gu a k")
     apply (metis assms(1) assms(2) full_uguard_sum_same not_Some_eq)
      apply (cases "get_gu b k")
      using add_gu_def[of "get_gu b" "get_gu c"]
        add_gu_single.simps(1)[of "get_gu c k"] assms(1) assms(2) compatible_def[of b c] compatible_def[of b' c]
        option.inject option.simps(3) plus.elims plus_extract(3)[of a b c]
      apply metis
  proof -
    fix ga gb assume "get_gu a k = Some ga" "get_gu b k = Some gb"
    then have "get_gu c k = None"
      by (metis assms(1) compatible_def compatible_eq option.simps(3))
    then show "get_gu b k = get_gu b' k"
      by (metis (no_types, opaque_lifting) add_gu_def add_gu_single.simps(1) assms(1) assms(2) plus_comm plus_extract(3))
    qed
  qed
  show "get_gs b = get_gs b'"
    by (metis add_gs_cancellative assms(1) assms(2) plus_extract(2))
  show "get_fh b = get_fh b'"
  proof (rule ext)
    fix l show "get_fh b l = get_fh b' l"
    proof (cases "get_fh a l")
      case None
      then have "get_fh b l = None"
        by (metis (no_types, lifting) add_fh_def assms(1) fadd_options.elims option.distinct(1) plus_extract(1))
      then show ?thesis
        by (metis (no_types, opaque_lifting) None add_fh_def assms(2) fadd_options.elims option.distinct(1) plus_extract(1))
    next
      case (Some aa)
      then have "get_fh a l = Some aa" by simp
      then show ?thesis
      proof (cases "get_fh c l")
        case None
        then show ?thesis
          by (metis (no_types, lifting) add_fh_def assms(1) assms(2) fadd_options.simps(1) plus_comm plus_extract(1))
      next
        case (Some cc)
        then have "get_fh c l = Some cc" by simp
        then show ?thesis using fadd_options_cancellative
          by (metis (no_types, opaque_lifting) add_fh_def assms(1) assms(2) plus_extract(1))
      qed
    qed
  qed
qed
lemma addition_cancellative3:
  assumes "Some x = Some a ⊕ Some b ⊕ Some c"
      and "Some x = Some a' ⊕ Some b ⊕ Some c"
    shows "a = a'"
proof -
  obtain ab ab' where "Some ab = Some a ⊕ Some b" "Some ab' = Some a' ⊕ Some b"
    by (metis assms(1) assms(2) not_Some_eq plus.simps(1))
  then have "ab = ab'"
    by (metis addition_cancellative assms(1) assms(2))
  then show ?thesis
    using ‹Some ab = Some a ⊕ Some b› ‹Some ab' = Some a' ⊕ Some b› addition_cancellative by blast
qed
lemma larger3:
  assumes "Some x = Some a ⊕ Some b ⊕ Some c"
  shows "x ≽ b"
proof -
  obtain ab where "Some ab = Some a ⊕ Some b"
    by (metis assms not_Some_eq plus.simps(1))
  then show ?thesis
    by (metis (no_types, opaque_lifting) assms larger_def larger_trans plus_comm)
qed
lemma add_get_fh:
  assumes "Some x = Some a ⊕ Some b"
  shows "get_fh x = add_fh (get_fh a) (get_fh b)"
  by (metis assms fst_conv get_fh.elims option.discI option.sel plus.simps(3))
lemma sum_gs_one_none:
  assumes "Some x = Some a ⊕ Some b"
      and "get_gs b = None"
    shows "get_gs x = get_gs a"
  by (metis add_gs.simps(1) assms(1) assms(2) plus_comm plus_extract(2))
lemma sum_gs_one_some:
  assumes "Some x = Some a ⊕ Some b"
      and "get_gs a = Some (pa, ma)"
      and "get_gs b = Some (pb, mb)"
    shows "get_gs x = Some (padd pa pb, ma + mb)"
  by (metis add_gs.simps(3) assms(1) assms(2) assms(3) fst_conv plus_extract(2) snd_conv)
definition empty_heap :: "('i, 'a) heap" where
  "empty_heap = (Map.empty, None, λk. None)"
lemma dom_normalize:
  "dom h = dom (normalize h)"
  by (meson FractionalHeap.normalize_eq(1) domIff subsetI subset_antisym)
lemma sum_second_none_get_fh:
  assumes "Some x = Some a ⊕ Some b"
      and "get_fh b l = None"
    shows "get_fh x l = get_fh a l"
proof (cases "get_fh a l")
  case None
  then show ?thesis
    by (metis (no_types, opaque_lifting) add_fh_def add_get_fh assms(1) assms(2) fadd_options.simps(1))
next
  case (Some aa)
  then show ?thesis
    by (metis (no_types, lifting) add_fh_def add_get_fh assms(1) assms(2) fadd_options.simps(2))
qed
lemma sum_first_none_get_fh:
  assumes "Some x = Some a ⊕ Some b"
      and "get_fh a l = None"
    shows "get_fh x l = get_fh b l"
  by (metis assms(1) assms(2) plus_comm sum_second_none_get_fh)
lemma dom_sum_two:
  assumes "Some x = Some a ⊕ Some b"
  shows "dom (get_fh x) = dom (get_fh a) ∪ dom (get_fh b)"
  by (metis add_get_fh assms compatible_def compatible_dom_sum compatible_eq option.distinct(1))
lemma dom_three_sum:
  assumes "Some x = Some a ⊕ Some b ⊕ Some c"
  shows "dom (get_fh x) = dom (get_fh a) ∪ dom (get_fh b) ∪ dom (get_fh c)"
proof -
  obtain ab where "Some ab = Some a ⊕ Some b"
    by (metis assms not_Some_eq plus.simps(1))
  then have "Some x = Some ab ⊕ Some c"
    using assms by presburger
  then have "dom (get_fh x) = dom (get_fh ab) ∪ dom (get_fh c)"
    by (meson dom_sum_two)
  then show ?thesis
    by (metis ‹Some ab = Some a ⊕ Some b› dom_sum_two)
qed
lemma addition_smaller_domain:
  assumes "Some a = Some b ⊕ Some c"
  shows "dom (get_fh b) ⊆ dom (get_fh a)"
  by (metis (no_types, opaque_lifting) Un_subset_iff assms dom_sum_two order_refl)
lemma one_value_sum_same:
  assumes "Some x = Some a ⊕ Some b"
      and "get_fh a l = Some (π, v)"
    shows "∃π'. get_fh x l = Some (π', v)"
  using assms(1) assms(2) not_Some_eq plus_extract_point_fh[of x a _ l "(π, v)"] snd_eqD sum_second_none_get_fh[of x a]
  by metis
lemma compatible_last_two:
  assumes "Some x = Some a ⊕ Some b ⊕ Some c"
  shows "b ## c"
  by (metis assms compatible_eq option.discI plus.simps(2) plus_asso)
lemma add_fh_map_empty:
  "add_fh h Map.empty = h"
proof (rule ext)
  fix x show "add_fh h Map.empty x = h x"
    by (metis add_fh_def fadd_options.simps(1) fadd_options.simps(2) not_None_eq)
qed
definition bounded where
  "bounded h ⟷ (∀l p. fst h l = Some p ⟶ pgte pwrite (fst p))"
lemma boundedI:
  assumes "⋀l p. fst h l = Some p ⟹ pgte pwrite (fst p)"
  shows "bounded h"
  by (simp add: assms bounded_def)
lemma boundedE:
  assumes "bounded h"
      and "fst h l = Some p"
    shows "pgte pwrite (fst p)"
  by (meson assms(1) assms(2) bounded_def)
lemma bounded_smaller_sum:
  assumes "bounded x"
      and "Some x = Some a ⊕ Some b"
    shows "bounded a"
proof (rule boundedI)
  fix l p assume asm0: "fst a l = Some p"
  then obtain p' where "fst x l = Some p'"
    by (metis assms(2) get_fh.simps one_value_sum_same prod.collapse)
  then have "pgte (fst p') (fst p)"
    apply (cases "fst b l")
     apply (metis (no_types, lifting) add_fh_def add_get_fh asm0 assms(2) fadd_options.simps(2) get_fh.elims not_pgte_charact option.sel pgt_implies_pgte)
    using add_fh_def[of "fst a" "fst b" l] asm0 assms(2) fadd_options.elims[of "fst a l" "fst b l"]
      fst_eqD get_fh.simps option.discI option.sel pgt_implies_pgte plus.simps(3)[of a b] sum_larger[of ]
    by metis
  then show "pgte pwrite (fst p)"
    by (meson ‹fst x l = Some p'› assms(1) boundedE dual_order.trans pgte.rep_eq)
qed
lemma bounded_smaller:
  assumes "bounded x"
      and "x ≽ a"
    shows "bounded a"
  using assms(1) assms(2) bounded_smaller_sum larger_def by blast
lemma sum_perm_smaller:
  assumes "Some x = Some a ⊕ Some b"
      and "fst a l = Some (p, v)"
    shows "∃p'. pgte p' p ∧ fst x l = Some (p', v)"
  apply (cases "fst b l")
   apply (metis assms(1) assms(2) get_fh.simps order.refl pgte.rep_eq sum_second_none_get_fh)
  apply clarsimp
  using assms(2) fst_eqD get_fh.simps pgt_implies_pgte plus_extract_point_fh[OF assms(1)] snd_eqD sum_larger
  by simp
lemma modus_ponens:
  assumes A
      and "A ⟹ B"
    shows B
  using assms by simp
lemma fpdom_inclusion:
  assumes "Some h' = Some h ⊕ Some r"
      and "bounded h'"
  shows "fpdom (fst h) ⊆ fpdom (fst h')"
  apply rule
  unfolding fpdom_def apply simp
  apply (erule exE)
  subgoal for x v
    apply (rule modus_ponens[of "∃p. fst h' x = Some (p, v)"])
     apply (metis assms(1) get_fh.simps one_value_sum_same)
    apply (erule exE)
    subgoal for p
      apply (rule modus_ponens[of "pgte pwrite p"])
       apply (metis assms(2) boundedE fst_conv)
      apply (rule modus_ponens[of "pgte p pwrite"])
      apply (metis Pair_inject assms(1) option.inject sum_perm_smaller)
      using pgte_antisym by blast
    done
  done
lemma fpdom_dom_disjoint:
  assumes "Some h = Some h1 ⊕ Some h2"
  shows "dom (fst h1) ∩ fpdom (fst h2) = {}"
  apply rule
   apply rule
  unfolding dom_def fpdom_def apply simp_all
  apply (erule conjE)
  apply (erule exE)+
    by (metis (no_types, lifting) assms fst_eqD get_fh.simps not_pgte_charact plus_comm plus_extract_point_fh sum_larger)
lemma fpdom_dom_union:
  assumes "Some h = Some h1 ⊕ Some h2"
      and "bounded h"
  shows "fpdom (fst h1) ∪ fpdom (fst h2) ⊆ fpdom (fst h)"
  by (metis assms fpdom_inclusion plus_comm sup_least)
lemma full_ownership_then_bounded:
  assumes "full_ownership (fst h)"
  shows "bounded h"
  apply (rule boundedI)
  by (metis assms full_ownership_def pgte.rep_eq pwrite.rep_eq rel_simps(47))
end