Theory Heap

(*<*)
theory Heap
imports
  Ix
  "ConcurrentHOL.ConcurrentHOL"
begin

(*>*)
section‹ A polymorphic heap\label{sec:CImperativeHOL-heap} ›

text‹

We model a heap as a partial map from opaque addresses to structured objects.
  we use this extra structure to handle buffered writes (see \S\ref{sec:tso})
  allocation is non-deterministic and partial
  supports explicit deallocation

Limitations:
  does not support polymorphic sum types such as typ'a + 'b and typ'a option or products or lists
  the class of representable types is too small to represent processes

Source materials:
  🗏‹$ISABELLE_HOME/src/HOL/Imperative_HOL/Heap.thy›
   that model of heaps includes a lim› field to support deterministic allocation
   it uses distinct heaps for arrays and references

›

setup Sign.mandatory_path "heap"

type_synonym addr = nat ―‹ untyped heap addresses ›

datatype rep ―‹ the concrete representation of heap values ›
  = Addr nat heap.addr ―‹ metadata paired with an address ›
  | Val nat

datatype "write" = Write heap.addr nat heap.rep

type_synonym t = "heap.addr  heap.rep list" ―‹ partial map from addresses to structured encoded values ›

abbreviation empty :: "heap.t" where
  "empty  Map.empty"

primrec apply_write :: "heap.write  heap.t  heap.t" where
  "apply_write (heap.Write addr i x) s = s(addr  (the (s addr))[i := x])"

(* the free tyvar warning is the same as for ‹countable› *)
class rep = ―‹ the class of representable types ›
  assumes ex_inj: "to_heap_rep :: 'a  heap.rep. inj to_heap_rep"

setup Sign.mandatory_path "rep"

lemma countable_classI[intro!]:
  shows "OFCLASS('a::countable, heap.rep_class)"
by intro_classes (simp add: inj_on_def exI[where x="heap.Val  to_nat"])

definition to :: "'a::heap.rep  heap.rep" where
  "to = (SOME f. inj f)"

definition "from" :: "heap.rep  'a::heap.rep" where
  "from = inv (heap.rep.to :: 'a  heap.rep)"

lemmas inj_to[simp] = someI_ex[OF heap.ex_inj, folded heap.rep.to_def]

lemma inj_on_to[simp, intro]: "inj_on heap.rep.to S"
using heap.rep.inj_to by (auto simp: inj_on_def)

lemma surj_from[simp]: "surj heap.rep.from"
unfolding heap.rep.from_def by (simp add: inj_imp_surj_inv)

lemma to_split[simp]: "heap.rep.to x = heap.rep.to y  x = y"
using injD[OF heap.rep.inj_to] by auto

lemma from_to[simp]:
  shows "heap.rep.from (heap.rep.to x) = x"
by (simp add: heap.rep.from_def)

instance unit :: heap.rep ..

instance bool :: heap.rep ..

instance nat :: heap.rep ..

instance int :: heap.rep ..

instance char :: heap.rep ..

instance String.literal :: heap.rep ..

instance typerep :: heap.rep ..

setup Sign.parent_path

text‹

User-facing heap types typically carry more information than an
(untyped) address, such as (phantom) typing and a representation
invariant that guarantees the soundness of the encoding (for the given
value at the given address only). We abstract over that here and provide
some generic operations.

Notes:
  intuitively addr_of› should be surjective but we do not enforce this
  we use sets here but these are not very flexible: all refs must have the same type
   this means some intutive facts involving UNIV› cannot be stated

›

class addr_of =
  fixes addr_of :: "'a  heap.addr"
  fixes rep_val_inv :: "'a  heap.rep list pred"

definition obj_at :: "heap.rep list pred  heap.addr  heap.t pred" where
  "obj_at P r s = (case s r of None  False | Some v  P v)"

abbreviation (input) present :: "'a::heap.addr_of  heap.t pred" where
  "present r  heap.obj_at True (heap.addr_of r)"

abbreviation (input) rep_inv :: "'a::heap.addr_of  heap.t pred" where
  "rep_inv r  heap.obj_at (heap.rep_val_inv r) (heap.addr_of r)"

abbreviation (input) rep_inv_set :: "'a::heap.addr_of  heap.t set" where
  "rep_inv_set r  Collect (heap.rep_inv r)"

―‹ allows arbitrary transitions provided the rep_inv› of r› is respected ›
abbreviation (input) rep_inv_rel :: "'a::heap.addr_of  heap.t rel" where
  "rep_inv_rel r  heap.rep_inv_set r × heap.rep_inv_set r"

―‹ totality models the idea that all dereferences are ``valid'' but only some are reasonable ›
definition get :: "'a::heap.addr_of  heap.t  'v::heap.rep list" where
  "get r s = map heap.rep.from (the (s (heap.addr_of r)))"

definition set :: "'a::heap.addr_of  'v::heap.rep list  heap.t  heap.t" where
  "set r v s = s(heap.addr_of r  map heap.rep.to v)"

definition dealloc :: "'a::heap.addr_of  heap.t  heap.t" where
  "dealloc r s = s |` {heap.addr_of r}"

―‹ allows no changes to rs›, asserts the rep_inv› of rs› is valid, arbitrary changes to -rs›
definition Id_on :: "'a::heap.addr_of set  heap.t rel" (heap.Id⇘_) where
  "heap.Id⇘rs= (rrs. heap.rep_inv_rel r  Id⇘λs. s (heap.addr_of r))"

―‹ allows arbitrary changes to rs› provided the rep_inv› of rs› is respected.
    requires addresses in -heap.addr_of ` rs› to be unchanged ›
definition modifies :: "'a::heap.addr_of set  heap.t rel" (heap.modifies⇘_) where
  "heap.modifies⇘rs= (rrs. heap.rep_inv_rel r)  {(s, s'). r-heap.addr_of ` rs. s r = s' r}"

setup Sign.mandatory_path "get"

lemma cong:
  assumes "s (heap.addr_of r) = s' (heap.addr_of r')"
  shows "heap.get r s = heap.get r' s'"
by (simp add: assms heap.get_def)

lemma Id_on_proj_cong:
  assumes "(s, s')  heap.Id⇘{r}⇙"
  shows "heap.get r s = heap.get r s'"
using assms by (simp add: heap.Id_on_def heap.get_def)

lemma fun_upd:
  shows "heap.get r (fun_upd s a (Some w))
      = (if heap.addr_of r = a then map heap.rep.from w else heap.get r s)"
by (simp add: heap.get_def)

lemma set_eq:
  shows "heap.get r (heap.set r v s) = v"
by (simp add: heap.get_def heap.set_def comp_def)

lemma set_neq:
  assumes "heap.addr_of r  heap.addr_of r'"
  shows "heap.get r (heap.set r' v s) = heap.get r s"
by (simp add: heap.get_def heap.set_def assms)

setup Sign.parent_path

setup Sign.mandatory_path "set"

lemma cong:
  assumes "heap.addr_of r = heap.addr_of r'"
  assumes "v = v'"
  assumes "r'. r'  heap.addr_of r  s r' = s' r'"
  shows "heap.set r v s = heap.set r' v' s'"
by (simp add: assms heap.set_def fun_eq_iff)

lemma empty:
  shows "heap.set r v (heap.empty) = [heap.addr_of r  map heap.rep.to v]"
by (simp add: heap.set_def)

lemma fun_upd:
  shows "heap.set r v (fun_upd s a w) = (fun_upd s a w)(heap.addr_of r  map heap.rep.to v)"
by (simp add: heap.set_def)

lemma same:
  shows "heap.set r v (heap.set r w s) = heap.set r v s"
by (simp add: heap.set_def)

lemma twist:
  assumes "heap.addr_of r  heap.addr_of r'"
  shows "heap.set r v (heap.set r' w s) = heap.set r' w (heap.set r v s)"
using assms by (simp add: heap.set_def fun_eq_iff)

setup Sign.parent_path

setup Sign.mandatory_path "obj_at"

lemma cong[cong]:
  fixes P :: "heap.rep list pred"
  assumes "v. s r = Some v  P v = P' v"
  assumes "r = r'"
  assumes "s r = s' r'"
  shows "heap.obj_at P r s  heap.obj_at P' r' s'"
using assms by (simp add: heap.obj_at_def cong: option.case_cong)

lemma split:
  shows "Q (heap.obj_at P r s)  (s r = None  Q False)  (v. s r = Some v  Q (P v))"
by (simp add: heap.obj_at_def split: option.splits)

lemma split_asm:
  shows "Q (heap.obj_at P r s)  ¬ ((s r = None  ¬Q False)  (v. s r = Some v  ¬ Q (P v)))"
by (simp add: heap.obj_at_def split: option.splits)

lemmas splits = heap.obj_at.split heap.obj_at.split_asm

lemma empty:
  shows "¬heap.obj_at P r heap.empty"
by (simp add: heap.obj_at_def)

lemma set:
  shows "heap.obj_at P r (heap.set r' v s)
     (r = heap.addr_of r'  P (map heap.rep.to v))  (r  heap.addr_of r'  heap.obj_at P r s)"
by (simp add: comp_def heap.set_def split: heap.obj_at.split)

lemma fun_upd:
  shows "heap.obj_at P r (fun_upd s a (Some w)) = (if r = a then P w else heap.obj_at P r s)"
by (simp split: heap.obj_at.split)

setup Sign.parent_path

lemmas simps = ―‹ objective: reduce manifest heaps ›
  heap.get.set_eq
  heap.get.fun_upd
  heap.set.empty
  heap.set.same
  heap.set.fun_upd
  heap.obj_at.empty
  heap.obj_at.fun_upd

setup Sign.mandatory_path "Id_on"

lemma empty[simp]:
  shows "heap.Id⇘{}= UNIV"
by (simp add: heap.Id_on_def)

lemma sup:
  shows "heap.Id⇘X  Y= heap.Id⇘X heap.Id⇘Y⇙"
unfolding heap.Id_on_def by blast

setup Sign.parent_path

setup Sign.mandatory_path "modifies"

lemma empty[simp]:
  shows "heap.modifies⇘{}= Id"
by (auto simp: heap.modifies_def)

lemma rep_inv_rel_le:
  shows "heap.modifies⇘rs (rrs. heap.rep_inv_rel r)"
by (simp add: heap.modifies_def)

lemma rep_inv:
  assumes "(s, s')  heap.modifies⇘{a}⇙"
  shows "heap.rep_inv a s"
    and "heap.rep_inv a s'"
using assms by (simp_all add: heap.modifies_def split: heap.obj_at.split)

lemma Id_conv:
  shows "(s, s)  heap.modifies⇘rs (rrs. (s, s)  heap.rep_inv_rel r)"
by (simp add: heap.modifies_def)

lemma eqI:
  assumes "(s, s')  heap.modifies⇘rs⇙"
  assumes "r. r  rs; heap.rep_inv r s; heap.rep_inv r s'  s (heap.addr_of r) = s' (heap.addr_of r)"
  shows "s = s'"
using assms by (simp add: heap.modifies_def) blast

setup Sign.parent_path

setup Sign.parent_path

setup Sign.mandatory_path "stable.heap"

lemma Id_on_frame_cong:
  assumes "s s'. (r. r  rs  heap.rep_inv r s  heap.rep_inv r s'  s (heap.addr_of r) = s' (heap.addr_of r))  P s  P' s'"
  shows "stable heap.Id⇘rsP  stable heap.Id⇘rsP'"
using assms by (auto 10 0 simp: stable_def monotone_def heap.Id_on_def)

lemma Id_on_frameI:
  assumes "s s'. (r. r  rs  heap.rep_inv r s  heap.rep_inv r s'  s (heap.addr_of r) = s' (heap.addr_of r))  P s  P s'"
  shows "stable heap.Id⇘rsP"
using assms by (auto simp: stable_def monotone_def heap.Id_on_def)

lemma Id_on_rep_invI[stable.intro]:
  assumes "r  rs"
  shows "stable heap.Id⇘rs(heap.rep_inv r)"
using assms by (blast intro: stable.heap.Id_on_frameI)

setup Sign.parent_path


subsection‹ References\label{sec:CImperativeHOL-heap-refs} ›

datatype 'a ref = Ref (addr_of: heap.addr)

instantiation ref :: (heap.rep) heap.addr_of
begin

definition addr_of_ref :: "'a ref  heap.addr" where
  "addr_of_ref = ref.addr_of"

definition rep_val_inv_ref :: "'a ref  heap.rep list pred" where
  "rep_val_inv_ref r vs  (case vs of [v]  heap.rep.to (heap.rep.from v :: 'a) = v | _ False)"

instance ..

end

instance ref :: (heap.rep) heap.rep
by standard (simp add: inj_on_def ref.expand exI[where x="heap.Addr 0  ref.addr_of"])

setup Sign.mandatory_path "Ref"

definition get :: "'a::heap.rep ref  heap.t  'a" where
  "get r s = hd (heap.get r s)"

definition set :: "'a::heap.rep ref  'a  heap.t  heap.t" where
  "set r v s = heap.set r [v] s"

definition alloc :: "'a  heap.t  ('a::heap.rep ref × heap.t) set" where
  "alloc v s = {(r, Ref.set r v s) |r. ¬heap.present r s}"

lemma addr_of:
  shows "heap.addr_of (Ref r) = r"
by (simp add: addr_of_ref_def)

setup Sign.mandatory_path "get"

lemma fun_upd:
  shows "Ref.get r (fun_upd s a (Some [w]))
      = (if heap.addr_of r = a then heap.rep.from w else Ref.get r s)"
by (simp add: Ref.get_def heap.simps)

lemma set_eq:
  shows "Ref.get r (Ref.set r v s) = v"
by (simp add: Ref.get_def Ref.set_def heap.simps)

lemma set_neq:
  fixes r :: "'a::heap.rep ref"
  fixes r' :: "'b::heap.rep ref"
  assumes "addr_of r  addr_of r'"
  shows "Ref.get r (Ref.set r' v s) = Ref.get r s"
using assms by (simp add: Ref.get_def Ref.set_def addr_of_ref_def heap.get.set_neq)

setup Sign.parent_path

setup Sign.mandatory_path "set"

lemma empty:
  shows "Ref.set r v (heap.empty) = [heap.addr_of r  [heap.rep.to v]]"
by (simp add: Ref.set_def heap.simps)

lemma fun_upd:
  shows "Ref.set r v (fun_upd s a w) = (fun_upd s a w)(heap.addr_of r  [heap.rep.to v])"
by (simp add: Ref.set_def heap.simps)

lemma same:
  shows "Ref.set r v (Ref.set r w s) = Ref.set r v s"
by (simp add: Ref.set_def heap.set_def)

lemma obj_at_conv:
  fixes a :: "heap.addr"
  fixes r :: "'a::heap.rep ref"
  fixes v :: "'a"
  fixes P :: "heap.rep list pred"
  shows "heap.obj_at P a (Ref.set r v s)  (a = heap.addr_of r  P [heap.rep.to v])
                                            (a  heap.addr_of r  heap.obj_at P a s)"
by (simp add: Ref.set_def heap.set_def split: heap.obj_at.split)

setup Sign.parent_path

lemmas simps[simp] =
  Ref.addr_of
  Ref.get.set_eq
  Ref.get.set_neq
  Ref.get.fun_upd
  Ref.set.same
  Ref.set.empty
  Ref.set.fun_upd
  Ref.set.obj_at_conv

setup Sign.parent_path


subsection‹ Arrays\label{sec:CImperativeHOL-heap-arrays} ›


subsubsection‹ Code generation constants: one-dimensional arrays ›

text‹

We ask that targets of the code generator provide implementations of one-dimensional arrays
and the associated operations.

Notes:
  user-facing arrays make use of classIx
  due to the lack of bounds there is no rep_val_inv›

datatype 'a one_dim_array = Array (addr_of: heap.addr)

instantiation one_dim_array :: (type) heap.addr_of
begin

definition addr_of_one_dim_array :: "'a one_dim_array  heap.addr" where
  "addr_of_one_dim_array = addr_of"

definition rep_val_inv_one_dim_array :: "'a one_dim_array  heap.rep list pred" where
[simp]: "rep_val_inv_one_dim_array a vs  True"

instance ..

end

setup Sign.mandatory_path "ODArray"

definition get :: "'a::heap.rep one_dim_array  nat  heap.t  'a" where
  "get a i s = heap.get a s ! i"

definition set :: "'a::heap.rep one_dim_array  nat  'a  heap.t  heap.t" where
  "set a i v s = heap.set a ((heap.get a s)[i:=v]) s"

definition alloc :: "'a list  heap.t  ('a::heap.rep one_dim_array × heap.t) set" where
  "alloc av s = {(a, heap.set a av s) |a. ¬heap.present a s}"

definition list_for :: "'a::heap.rep one_dim_array  heap.t  'a list" where
  "list_for a = heap.get a"

setup Sign.mandatory_path "get"

lemma weak_cong:
  assumes "i = i'"
  assumes "a = a'"
  assumes "s (heap.addr_of a) = s' (heap.addr_of a')"
  shows "ODArray.get a i s = ODArray.get a' i' s'"
using assms by (simp add: ODArray.get_def cong: heap.get.cong)

lemma weak_Id_on_proj_cong:
  assumes "i = i'"
  assumes "a = a'"
  assumes "(s, s')  heap.Id⇘{a'}⇙"
  shows "ODArray.get a i s = ODArray.get a' i' s'"
using assms by (simp add: ODArray.get_def cong: heap.get.Id_on_proj_cong)

lemma set_eq:
  assumes "i < length (the (s (heap.addr_of a)))"
  shows "ODArray.get a i (ODArray.set a i v s) = v"
using assms by (simp add: ODArray.get_def ODArray.set_def heap.get.set_eq) (simp add: heap.get_def)

lemma set_neq:
  assumes "i  j"
  shows "ODArray.get a i (ODArray.set a j v s) = ODArray.get a i s"
using assms by (simp add: ODArray.get_def ODArray.set_def heap.get.set_eq)

setup Sign.parent_path

setup Sign.parent_path


subsubsection‹ User-facing arrays ›

datatype ('i, 'a) array = Array (bounds: "('i × 'i)") (arr: "'a one_dim_array")

hide_const (open) bounds arr

instantiation array :: (Ix, heap.rep) heap.addr_of
begin

definition addr_of_array :: "('a, 'b) array  heap.addr" where
  "addr_of_array = addr_of  array.arr"

definition rep_val_inv_array :: "('a, 'b) array  heap.rep list pred" where
  "rep_val_inv_array a vs 
      length vs = length (Ix.interval (array.bounds a))
     (vset vs. heap.rep.to (heap.rep.from v :: 'b) = v)"

instance ..

end

instance array :: (countable, type) heap.rep
by standard
   (rule exI[where x="λa. heap.Addr (to_nat (array.bounds a)) (addr_of (array.arr a))"],
         rule injI, simp add: array.expand one_dim_array.expand)

setup Sign.mandatory_path "Array"

abbreviation (input) square :: "('i::Ix × 'i, 'a) array  bool" where
  "square a  Ix.square (array.bounds a)"

abbreviation (input) index :: "('i::Ix, 'a) array  'i  nat" where
  "index a  Ix.index (array.bounds a)"

abbreviation (input) interval :: "('i::Ix, 'a) array  'i list" where
  "interval a  Ix.interval (array.bounds a)"

definition get :: "('i::Ix, 'a::heap.rep) array  'i  heap.t  'a" where
  "get a i = ODArray.get (array.arr a) (Array.index a i)"

definition set :: "('i::Ix, 'a::heap.rep) array  'i  'a  heap.t  heap.t" where
  "set a i v = ODArray.set (array.arr a) (Array.index a i) v"

definition list_for :: "('i::Ix, 'a::heap.rep) array  heap.t  'a list" where
  "list_for a = ODArray.list_for (array.arr a)"

―‹ can coerce any indexing regime into any other provided the contents fit ›
definition coerce :: "('i::Ix, 'a::heap.rep) array  ('j × 'j)  ('j::Ix, 'a::heap.rep) array option" where
  "coerce a b = (if length (Array.interval a) = length (Ix.interval b)
                 then Some (Array b (array.arr a))
                 else None)"

definition Id_on :: "('i::Ix, 'a::heap.rep) array  'i set  heap.t rel" (Array.Id⇘_, _) where
  "Array.Id⇘a, is= heap.rep_inv_rel a  {(s, s'). iis. Array.get a i s = Array.get a i s'}"

definition modifies :: "('i::Ix, 'a::heap.rep) array  'i set  heap.t rel" (Array.modifies⇘_, _) where
  "Array.modifies⇘a, is= heap.modifies⇘{a} {(s, s'). iset (Array.interval a) - is. Array.get a i s = Array.get a i s'}"

lemma simps[simp]:
  shows "heap.addr_of (array.arr a) = heap.addr_of a"
    and "heap.addr_of  array.arr = heap.addr_of"
by (simp_all add: addr_of_array_def addr_of_one_dim_array_def)

setup Sign.mandatory_path "get"

lemma set_eq:
  assumes "heap.rep_inv a s"
  assumes "i  set (Array.interval a)"
  shows "Array.get a i (Array.set a i v s) = v"
using assms
by (simp add: Array.get_def Array.set_def ODArray.get.set_eq index_length rep_val_inv_array_def
       split: heap.obj_at.split_asm)

lemma set_neq:
  assumes "i  set (Array.interval a)"
  assumes "j  set (Array.interval a)"
  assumes "i  j"
  shows "Array.get a j (Array.set a i v s) = Array.get a j s"
using assms by (simp add: Array.get_def Array.set_def ODArray.get.set_neq index_eq_conv)

lemma Id_on_proj_cong:
  assumes "a = a'"
  assumes "i = i'"
  assumes "(s, s')  Array.Id⇘a', {i'}⇙"
  assumes "i'  set (Array.interval a)"
  shows "Array.get a i s = Array.get a' i' s'"
using assms by (simp add: Array.get_def Array.Id_on_def)

lemma weak_cong:
  assumes "a = a'"
  assumes "i = i'"
  assumes "s (heap.addr_of a) = s' (heap.addr_of a')"
  shows "Array.get a i s = Array.get a' i' s'"
using assms unfolding Array.get_def by (simp cong: ODArray.get.weak_cong)

lemma weak_Id_on_proj_cong:
  assumes "i = i'"
  assumes "a = a'"
  assumes "(s, s')  heap.Id⇘{a'}⇙"
  shows "Array.get a i s = Array.get a' i' s'"
using assms unfolding Array.get_def
by (simp add: heap.Id_on_def  ODArray.get.weak_Id_on_proj_cong split: heap.obj_at.splits)

lemma ext:
  assumes "heap.rep_inv a s"
  assumes "heap.rep_inv a s'"
  assumes "iset (Ix_class.interval (array.bounds a)). Array.get a i s = Array.get a i s'"
  shows "s (heap.addr_of a) = s' (heap.addr_of a)"
using assms
by (simp add: Array.get_def ODArray.get_def heap.get_def rep_val_inv_array_def
       split: heap.obj_at.splits)
   (rule nth_equalityI, simp, metis index_forE nth_map nth_mem)

setup Sign.parent_path

setup Sign.mandatory_path "set"

lemma cong_deref:
  assumes "a = a'"
  assumes "i = i'"
  assumes "v = v'"
  assumes "s r = s' r'"
  assumes "r = r'"
  shows "Array.set a i v s r = Array.set a' i' v' s' r'"
using assms by (clarsimp simp: Array.set_def ODArray.set_def heap.set_def heap.get_def)

lemma same:
  shows "Array.set a i v (Array.set a i v' s) = Array.set a i v s"
by (simp add: Array.set_def ODArray.set_def heap.simps)

setup Sign.parent_path

setup Sign.mandatory_path "coerce"

lemma ex_bij_betw:
  fixes a :: "('i::Ix, 'a::heap.rep) array"
  fixes b :: "'j::Ix × 'j"
  assumes "Array.coerce a b = Some a'"
  obtains f where "map f (Array.interval a) = Ix.interval b"
using assms unfolding Array.coerce_def by (metis interval map_map map_nth not_None_eq)

lemma ex_bij_betw2:
  fixes a :: "('i::Ix, 'a::heap.rep) array"
  fixes b :: "'j::Ix × 'j"
  assumes "Array.coerce a b = Some a'"
  obtains f where "map f (Ix.interval b) = Array.interval a"
using assms by (metis Array.coerce_def Array.coerce.ex_bij_betw array.sel(1) option.distinct(1))

setup Sign.parent_path

setup Sign.mandatory_path "rep_inv"

lemma set:
  assumes "heap.rep_inv a s"
  shows "heap.rep_inv a (Array.set a i v s)"
using assms
by (simp add: Array.set_def ODArray.set_def rep_val_inv_array_def heap.set_def heap.get_def
       split: heap.obj_at.splits)

setup Sign.parent_path

setup Sign.mandatory_path "modifies"

lemma heap_modifies_le:
  shows "Array.modifies⇘a, is heap.modifies⇘{a}⇙"
by (simp add: Array.modifies_def)

lemma heap_rep_inv_rel_le:
  shows "Array.modifies⇘a, is heap.rep_inv_rel a"
using heap.modifies.rep_inv_rel_le[where rs="{a}"] by (auto simp: Array.modifies_def)

lemma empty:
  shows "Array.modifies⇘a, {}= Id  heap.rep_inv_rel a" (is "?lhs = ?rhs")
by (auto simp: Array.modifies_def heap.modifies.Id_conv heap.modifies.rep_inv
         elim: heap.modifies.eqI Array.get.ext)

lemma mono:
  assumes "is  js"
  shows "Array.modifies⇘a, is Array.modifies⇘a, js⇙"
using assms by (auto simp: Array.modifies_def)

lemma INTER:
  shows "Array.modifies⇘a, xX. f x= (xX. Array.modifies⇘a, f x)  heap.modifies⇘{a}⇙"
by (auto simp: Array.modifies_def)

lemma Inter:
  shows "Array.modifies⇘a, X= (xX. Array.modifies⇘a, x)  heap.modifies⇘{a}⇙"
by (auto simp: Array.modifies_def)

lemma inter:
  shows "Array.modifies⇘a, is Array.modifies⇘a, js= Array.modifies⇘a, is  js⇙"
by (auto simp: Array.modifies_def)

lemma UNION_subseteq:
  shows "(xX. Array.modifies⇘a, I x)  Array.modifies⇘a, (xX. I x)⇙"
by (simp add: Array.modifies.mono Sup_upper UN_least)

lemma union_subseteq:
  shows "Array.modifies⇘a, is Array.modifies⇘a, js Array.modifies⇘a, is  js⇙"
by (simp add: Array.modifies.mono)

lemma Diag_subseteq:
  assumes "s. P s  heap.rep_inv a s"
  shows "Diag P  Array.modifies⇘a, is⇙"
using assms by (auto simp: Array.modifies_def heap.modifies_def Diag_def)

lemma get:
  assumes "(s, s')  Array.modifies⇘a, is⇙"
  assumes "i  set (Array.interval a) - is"
  shows "Array.get a i s' = Array.get a i s"
using assms by (simp add: Array.modifies_def)

lemma set:
  assumes "heap.rep_inv a s"
  shows "(s, Array.set a i v s)  heap.modifies⇘{a}⇙"
using assms
by (simp add: heap.modifies_def Array.set_def ODArray.set_def heap.set_def heap.get_def rep_val_inv_array_def 
       split: heap.obj_at.splits)

lemma Array_set:
  assumes "heap.rep_inv a s"
  assumes "i  set (Array.interval a)  is"
  shows "(s, Array.set a i v s)  Array.modifies⇘a, is⇙"
using assms
by (auto simp: Array.modifies_def Array.rep_inv.set Array.modifies.set
        intro: Array.get.set_neq[symmetric])

lemma Array_set_conv:
  assumes "i  set (Array.interval a)  is"
  shows "(s, Array.set a i v s)  Array.modifies⇘a, is heap.rep_inv a s" (is "?lhs  ?rhs")
proof(rule iffI)
  show "?lhs  ?rhs"
   using heap.modifies.rep_inv_rel_le[of "{a}", simplified] by (auto simp: Array.modifies_def)
  from assms show "?rhs  ?lhs"
    by (simp add: Array.modifies.Array_set)
qed

setup Sign.parent_path

lemmas simps' =
  Array.rep_inv.set
  Array.get.set_eq

setup Sign.parent_path

setup Sign.mandatory_path "heap.Id_on.Array"

lemma Id_on_le:
  shows "heap.Id⇘{a} Array.Id⇘a, is⇙"
by (auto simp: Array.Id_on_def heap.Id_on_def Array.get_def ODArray.get_def heap.get_def)

setup Sign.parent_path

setup Sign.mandatory_path "Array.Id_on"

lemma empty:
  shows "Array.Id⇘a, {}= heap.rep_inv_rel a"
by (simp add: Array.Id_on_def)

lemma mono:
  assumes "is  js"
  shows "Array.Id⇘a, js Array.Id⇘a, is⇙"
using assms by (auto simp: Array.Id_on_def)

lemma insert:
  shows "Array.Id⇘a, insert i is= Array.Id⇘a, {i} Array.Id⇘a, is⇙"
by (fastforce simp: Array.Id_on_def)

lemma union:
  shows "Array.Id⇘a, is  js= Array.Id⇘a, is Array.Id⇘a, js⇙"
by (fastforce simp: Array.Id_on_def)

lemma rep_inv_rel:
  shows "Array.Id⇘a, is heap.rep_inv_rel a"
by (simp add: Array.Id_on_def)

lemma eq_heap_Id_on:
  assumes "set (Array.interval a)  is"
  shows "Array.Id⇘a, is= heap.Id⇘{a}⇙"
by (rule antisym[OF _ heap.Id_on.Array.Id_on_le])
   (use assms in force simp: Array.Id_on_def heap.Id_on_def elim: Array.get.ext)

setup Sign.parent_path


subsubsection‹ Stability\label{sec:CImperativeHOL-heap-stability} ›

setup Sign.mandatory_path "stable.heap.Id_on.Array"

lemma get[stable.intro]:
  assumes "a  as"
  shows "stable heap.Id⇘as(λs. P (Array.get a i s))"
using assms by (auto simp: stable_def monotone_def heap.Id_on_def cong: Array.get.weak_cong)

lemma get_chain: ―‹ difficult to apply ›
  assumes "v. stable heap.Id⇘as(P v)"
  assumes "a  as"
  shows "stable heap.Id⇘as(λs. P (Array.get a i s) s)"
using assms by (auto simp: stable_def monotone_def heap.Id_on_def cong: Array.get.weak_cong)

setup Sign.parent_path

setup Sign.mandatory_path "stable.Array.Id_on.Array"

lemma get[stable.intro]:
  assumes "i  is"
  shows "stable Array.Id⇘a, is(λs. P (Array.get a i s))"
using assms by (auto simp: stable_def monotone_def Array.Id_on_def)

lemma get_chain: ―‹ difficult to apply ›
  assumes "v. stable Array.Id⇘a, is(P v)"
  assumes "i  is"
  shows "stable Array.Id⇘a, is(λs. P (Array.get a i s) s)"
using assms by (auto simp: stable_def monotone_def Array.Id_on_def)

setup Sign.parent_path

setup Sign.mandatory_path "stable.heap.Array.Id_on.heap"

lemma rep_inv[stable.intro]:
  shows "stable Array.Id⇘a, is(heap.rep_inv a)"
by (simp add: stable_def monotone_def Array.Id_on_def)

setup Sign.parent_path

setup Sign.mandatory_path "stable.heap.Array.modifies.heap"

lemma rep_inv[stable.intro]:
  shows "stable Array.modifies⇘a, is(heap.rep_inv a)"
by (simp add: stable_def monotone_def Array.modifies_def heap.modifies_def)

setup Sign.parent_path

setup Sign.mandatory_path "stable.heap.Array.modifies.Array"

lemma get[stable.intro]:
  assumes "i  set (Array.interval a) - is"
  shows "stable Array.modifies⇘a, is(λs. P (Array.get a i s))"
using assms by (simp add: stable_def monotone_def Array.modifies_def)

lemma get_chain: ―‹ difficult to apply ›
  assumes "v. stable Array.modifies⇘a, is(P v)"
  assumes "i  set (Array.interval a) - is"
  shows "stable Array.modifies⇘a, is(λs. P (Array.get a i s) s)"
using assms by (simp add: stable_def monotone_def Array.modifies_def)

setup Sign.parent_path
(*<*)

end
(*>*)