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
datatype rep
= Addr nat heap.addr
| Val nat
datatype "write" = Write heap.addr nat heap.rep
type_synonym t = "heap.addr ⇀ heap.rep list"
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])"
class rep =
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)"
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"
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}"
definition Id_on :: "'a::heap.addr_of set ⇒ heap.t rel" (‹heap.Id⇘_⇙›) where
"heap.Id⇘rs⇙ = (⋂r∈rs. heap.rep_inv_rel r ∩ Id⇘λs. s (heap.addr_of r)⇙)"
definition modifies :: "'a::heap.addr_of set ⇒ heap.t rel" (‹heap.modifies⇘_⇙›) where
"heap.modifies⇘rs⇙ = (⋂r∈rs. 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 =
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⇙ ⊆ (⋂r∈rs. 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⇙ ⟷ (∀r∈rs. (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⇘rs⇙ P ⟷ stable heap.Id⇘rs⇙ P'"
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⇘rs⇙ P"
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} ›