theory Perm
imports Main Rat VHelper Lang
begin
This file contains a soundness proof for CSL with multiple resources
and permissions.
(Adapted to Isabelle 2016-1 by Qin Yu and James Brotherston)
Permission model
Fractional permissions are rational numbers in the range (0,1].
typedef myfrac = {x::rat. 0 < x ∧ x ≤ 1}
by (rule_tac x=0.5 in exI, simp)
definition pfull ≜ Abs_myfrac 1 — Full permission
type_synonym pheap = (nat ⇀ nat * myfrac) — Permission heaps
type_synonym pstate = stack × pheap — Permission states
Definition when two permission heaps are composable.
definition
pdisj :: pheap ⇒ pheap ⇒ bool
where
pdisj h1 h2 ≜ (∀x. case h1 x of None ⇒ True | Some y1 ⇒
(case h2 x of None ⇒ True | Some y2 ⇒
fst y1 = fst y2 ∧
Rep_myfrac (snd y1) + Rep_myfrac (snd y2) ≤ 1))
Composition of two permission heaps.
definition
padd :: pheap ⇒ pheap ⇒ pheap
where
padd h1 h2 ≜
(λx. case h1 x of None ⇒ h2 x | Some y1 ⇒
(case h2 x of None ⇒ h1 x | Some y2 ⇒
Some (fst y1, Abs_myfrac (Rep_myfrac (snd y1) + Rep_myfrac (snd y2)))))
Composition of two permission heaps, better for automation.
definition
mypadd :: pheap option ⇒ pheap option ⇒ pheap option
(infixr ⊕ 100)
where
xo ⊕ yo ≜ case xo of None ⇒ None | Some x ⇒
(case yo of None ⇒ None | Some y ⇒
if pdisj x y then Some (padd x y) else None)
Full-permission domain of a permission heap
definition fpdom h ≜ {x. ∃v. h x = Some (v, pfull)}
Mapping from permission heaps to normal heaps
definition
ptoheap :: pheap option ⇒ heap ⇒ bool
where
ptoheap ho h ≜ case ho of None ⇒ False | Some ha ⇒
(∀x. case ha x of None ⇒ h x = None | Some y ⇒
snd y = pfull ∧ h x = Some (fst y))
Basic properties of fractions in the range (0,1]
lemmas rat_simps =
add_rat eq_rat one_rat zero_rat mult_rat le_rat minus_rat diff_rat
lemmas frac_simps =
Rep_myfrac_inverse Rep_myfrac Abs_myfrac_inverse Abs_myfrac_inject
lemma frac_contra[simp]:
¬ (Rep_myfrac pfull + Rep_myfrac b ≤ 1)
¬ (Rep_myfrac b + Rep_myfrac pfull ≤ 1)
by (case_tac b, auto simp add: pfull_def frac_simps)+
lemma frac_pos:
by (case_tac x, simp add: frac_simps)
lemma frac_pos2[simp]:
0 < Rep_myfrac x + Rep_myfrac y
0 < Rep_myfrac x + (Rep_myfrac y + Rep_myfrac z)
by (case_tac x, (case_tac y)?, (case_tac z)?, simp add: frac_simps)+
Properties of permission-heaps
by (clarsimp simp add: pdisj_def split: option.splits)+
lemma pdisj_upd:
h x = Some (w, pfull)
pdisj (h(x ↦ (v, pfull))) h' = pdisj h h'
by (simp add: pdisj_def, rule iff_allI, auto split: option.splits)
lemma pdisj_comm:
pdisj h1 h2 = pdisj h2 h1
by (fastforce split: option.splits simp add: pdisj_def)
lemma padd_empty[simp]:
by (rule ext, clarsimp simp add: padd_def split: option.splits)+
lemma padd_comm[simp]:
pdisj x y
padd y x = padd x y
by (fastforce split: option.splits simp add: padd_def pdisj_def algebra_simps)
lemma pdisj_padd:
pdisj y z ; pdisj x (padd y z)
(pdisj x y ∧ pdisj x z)
apply (clarsimp simp add: pdisj_def padd_def all_conj_distrib [symmetric])
apply (drule_tac a=xa in allD)+
apply (auto split: option.splits simp add: algebra_simps frac_simps)
apply (cut_tac x=be in frac_pos, simp)
apply (cut_tac x=bd in frac_pos, simp)
done
lemma pdisjE[elim]:
pdisj x (padd y z) ; pdisj y z
pdisj x y
pdisj x (padd y z) ; pdisj y z
pdisj x z
by (drule (1) pdisj_padd, simp)+
lemma pdisj_padd_comm:
pdisj y (padd x z); pdisj x z
pdisj x (padd y z)
apply (clarsimp simp add: pdisj_def padd_def all_conj_distrib [symmetric])
apply (drule_tac a=xa in allD)+
apply (auto split: option.splits simp add: algebra_simps frac_simps)
apply (subst Abs_myfrac_inverse, simp add: frac_simps)
apply (cut_tac x=bf in frac_pos, simp)
apply (cut_tac x=bd in frac_pos, simp)
done
lemma pdisj_padd_expand:
pdisj x y
pdisj (padd x y) z = (pdisj x (padd y z) ∧ pdisj y z)
apply (simp add: pdisj_comm, rule iffI)
apply (frule (1) pdisj_padd_comm)
apply (drule (1) pdisj_padd, subst padd_comm, simp_all add: pdisj_comm)
apply (clarify, rule pdisj_padd_comm, simp_all add: pdisj_comm)
done
lemma padd_assoc:
pdisj x (padd y z) ; pdisj y z
padd (padd x y) z = padd x (padd y z)
apply (clarsimp simp add: pdisj_def padd_def all_conj_distrib [symmetric], rule ext)
apply (drule_tac a=xa in allD)+
apply (auto split: option.splits simp add: algebra_simps frac_simps)
apply (subst Abs_myfrac_inverse, simp_all add: frac_simps)
apply (cut_tac x=be in frac_pos, simp)
done
lemma padd_left_comm:
pdisj x (padd y z) ; pdisj y z
padd x (padd y z) = padd y (padd x z)
apply (clarsimp simp add: pdisj_def padd_def all_conj_distrib [symmetric], rule ext)
apply (drule_tac a=xa in allD)+
apply (auto split: option.splits simp add: algebra_simps frac_simps)
apply (subst Abs_myfrac_inverse, simp_all add: frac_simps)
apply (cut_tac x=bf in frac_pos, simp)
done
lemma padd_cancel:
padd x y = padd x z ; pdisj x y; pdisj x z
y = z
apply (clarsimp simp add: pdisj_def padd_def all_conj_distrib [symmetric], rule ext)
apply (drule_tac a=xa in allD |drule_tac x=xa in fun_cong)+
apply (auto split: option.splits simp add: algebra_simps frac_simps)
apply (case_tac b, case_tac ba, clarsimp simp add: frac_simps)
apply (case_tac b, case_tac ba, clarsimp simp add: frac_simps)
apply (case_tac b, case_tac ba, clarsimp simp add: frac_simps)
done
lemma dom_padd[simp]:
dom (padd x y) = dom x ∪ dom y
by (rule set_eqI, simp add: padd_def dom_def split: option.splits)
lemma fpdom_padd[elim]:
pdisj h1 h2
fpdom h1 ⊆ fpdom (padd h1 h2)
pdisj h1 h2
fpdom h2 ⊆ fpdom (padd h1 h2)
apply (auto simp add: fpdom_def pdisj_def padd_def disjoint_def split: option.splits)
apply (drule_tac a=x in allD, fastforce)+
done
lemma pa_empty[simp]:
by (auto simp add: mypadd_def split: option.splits)
lemma pa_none[simp]:
by (auto simp add: mypadd_def split: option.splits)
lemma pa_comm:
by (auto simp add: mypadd_def pdisj_comm split: option.splits)
lemma pa_assoc:
apply (auto simp add: mypadd_def padd_assoc pdisj_padd_expand split: option.splits)
apply (erule notE, fast)
done
lemma pa_left_comm:
apply (auto simp add: mypadd_def padd_left_comm split: option.splits)
apply (erule_tac[!] notE, (erule (1) pdisj_padd_comm |erule (1) pdisjE)+)
done
lemma some_padd:
pdisj h1 h2
Some (padd h1 h2) = Some h1 ⊕ Some h2
by (simp add: mypadd_def)
lemmas pa_ac = pa_comm pa_assoc pa_left_comm some_padd
lemma pa_cancel:
x ⊕ y = x ⊕ z; x ⊕ y ≠ None
y = z
apply (simp add: mypadd_def split: option.splits if_splits)
apply (clarify, erule (2) padd_cancel)
done
lemma ptoD:
ptoheap x z; ptoheap y z
x = y
apply (clarsimp simp add: ptoheap_def split: option.splits)
apply (rule ext)
apply ((drule_tac a=xa in allD)+, auto)
apply (case_tac x2a xa, case_tac x2 xa, simp_all, fast+)
done
lemma pdisj_search1:
ptoheap (Some x ⊕ Some y) hh
pdisj x y
ptoheap (Some x ⊕ Some y ⊕ z) hh
pdisj x y
ptoheap (Some x ⊕ z ⊕ Some y) hh
pdisj x y
ptoheap (Some x ⊕ z ⊕ Some y ⊕ w) hh
pdisj x y
ptoheap (Some x ⊕ z ⊕ w ⊕ Some y) hh
pdisj x y
ptoheap (Some x ⊕ z ⊕ w ⊕ Some y ⊕ v) hh
pdisj x y
ptoheap (z ⊕ Some x ⊕ Some y) hh
pdisj x y
ptoheap (z ⊕ Some x ⊕ Some y ⊕ w) hh
pdisj x y
ptoheap (z ⊕ Some x ⊕ w ⊕ Some y) hh
pdisj x y
ptoheap (z ⊕ Some x ⊕ w ⊕ Some y ⊕ v) hh
pdisj x y
ptoheap (z ⊕ Some x ⊕ w ⊕ v ⊕ Some y) hh
pdisj x y
ptoheap (z ⊕ w ⊕ Some x ⊕ Some y) hh
pdisj x y
ptoheap (z ⊕ w ⊕ Some x ⊕ Some y ⊕ v) hh
pdisj x y
ptoheap (z ⊕ w ⊕ Some x ⊕ v ⊕ Some y) hh
pdisj x y
apply (simp_all add: ptoheap_def mypadd_def, case_tac[!] pdisj x y, simp_all)
apply (auto split: option.splits if_split_asm)
apply (erule notE | fast | erule pdisjE [rotated])+
done
lemma pdisj_comm_implies:
by (fastforce split: option.splits simp add: pdisj_def)
lemmas pdisj_search[elim] =
pdisj_search1 pdisj_search1[THEN pdisj_comm_implies]
Assertions with permissions
datatype assn =
Aemp — Empty heap
| Apsto myfrac exp exp — Singleton heap
| Astar assn assn (infixl ** 100) — Separating conjunction
| Awand assn assn — Separating implication
| Apure bexp — Pure assertion
| Aconj assn assn — Conjunction
| Adisj assn assn — Disjunction
| Aex (nat ⇒ assn) — Existential quantification
Separating conjunction of a finite list of assertions is
just a derived assertion.
primrec
Aistar :: assn list ⇒ assn
where
Aistar [] = Aemp
| Aistar (P # Ps) = Astar P (Aistar Ps)
primrec
sat :: pstate ⇒ assn ⇒ bool (infixl ⊨ 60)
where
(σ ⊨ Aemp) = (snd σ = empty)
| (σ ⊨ Apsto k E E') = (dom (snd σ) = { edenot E (fst σ) } ∧ (snd σ) (edenot E (fst σ)) = Some (edenot E' (fst σ), k))
| (σ ⊨ P ** Q) = (∃h1 h2. (fst σ, h1) ⊨ P ∧ (fst σ, h2) ⊨ Q ∧ snd σ = padd h1 h2 ∧ pdisj h1 h2)
| (σ ⊨ Awand P Q) = (∀h. disjoint (dom (snd σ)) (dom h) ∧ (fst σ, h) ⊨ P ⟶ (fst σ, snd σ ++ h) ⊨ Q)
| (σ ⊨ Apure B) = bdenot B (fst σ)
| (σ ⊨ Aconj P Q) = (σ ⊨ P ∧ σ ⊨ Q)
| (σ ⊨ Adisj P Q) = (σ ⊨ P ∨ σ ⊨ Q)
| (σ ⊨ Aex PP) = (∃v. σ ⊨ PP v)
Shorthand for full permission
definition
Aptsto :: exp ⇒ exp ⇒ assn (
infixl ⟼ 200)
where
E ⟼ E' ≜ Apsto pfull E E'
lemma sat_Aptsto[simp]:
(σ ⊨ E ⟼ E') = (dom (snd σ) = { edenot E (fst σ) }
∧ (snd σ) (edenot E (fst σ)) = Some (edenot E' (fst σ), pfull))
by (simp add: Aptsto_def)
definition
implies :: assn ⇒ assn ⇒ bool (
infixl ⊑ 60)
where
P ⊑ Q ≜ (∀σ. σ ⊨ P ⟶ σ ⊨ Q)
lemma sat_istar_map_expand:
r ∈ set l
σ ⊨ Aistar (map f l)
⟷ (∃h1 h2. (fst σ, h1) ⊨ f r
∧ (fst σ, h2) ⊨ Aistar (map f (remove1 r l))
∧ snd σ = padd h1 h2 ∧ pdisj h1 h2)
apply (case_tac σ, rename_tac s h, clarify)
apply (induct l arbitrary: σ, simp_all, clarsimp, safe)
apply (intro exI conjI, simp+)
apply (drule pdisj_padd, simp, clarsimp)
apply (rule padd_left_comm, simp_all)
apply (rule pdisj_padd_comm, simp_all)
apply (intro exI conjI, simp+)
apply (drule pdisj_padd, simp, clarsimp)
apply (rule padd_left_comm, simp_all)
apply (rule pdisj_padd_comm, simp_all)
done
Precision
We say that an assertion is precise if for any given heap, there is at
most one subheap that satisfies the formula. (The formal definition below says
that if there are two such subheaps, they must be equal.)
definition
precise :: assn ⇒ bool
where
precise P ≜ ∀h1 h2 h1' h2' s. pdisj h1 h2 ∧ pdisj h1' h2'
∧ padd h1 h2 = padd h1' h2' ∧ (s, h1) ⊨ P ∧ (s, h1') ⊨ P
⟶ h1 = h1'
A direct consequence of the definition that is more useful in
Isabelle, because unfolding the definition slows down Isabelle's simplifier
dramatically.
lemma preciseD:
precise P; (s, x) ⊨ P; (s, x') ⊨ P; padd x y = padd x' y';
pdisj x y; pdisj x' y'
x = x' ∧ y = y'
unfolding precise_def
by (drule all5_impD, (erule conjI)+, simp_all, drule padd_cancel)
The separating conjunction of precise assertions is precise:
lemma precise_istar:
∀x ∈ set l. precise x
precise (Aistar l)
apply (induct l, simp_all (no_asm) add: precise_def)
apply (clarsimp simp add: padd_assoc pdisj_padd_expand)
apply (drule (3) preciseD, simp_all, clarsimp)
apply (drule (3) preciseD, simp_all)
done
Auxiliary definition for resource environments
definition
envs :: (
'a ⇒ assn) ⇒
'a list ⇒
'a list ⇒ assn
where
envs Γ l l' ≜ Aistar (map Γ (list_minus l l'))
lemma sat_envs_expand:
r ∈ set l; r ∉ set l'; distinct l
σ ⊨ envs Γ l l'
⟷ (∃h1 h2. (fst σ, h1) ⊨ Γ r
∧ (fst σ, h2) ⊨ envs Γ (removeAll r l) l'
∧ snd σ = padd h1 h2 ∧ pdisj h1 h2)
apply (simp add: envs_def distinct_remove1_removeAll [THEN sym] add: list_minus_remove1)
apply (subst sat_istar_map_expand [
where f=Γ
and r=r], simp_all)
done
lemma envs_upd:
r ∉ set l
envs (Γ(r := R)) l l' = envs Γ l l'
r ∈ set l'
envs (Γ(r := R)) l l' = envs Γ l l'
by (simp_all add: envs_def)
lemma envs_removeAll_irr:
r ∉ set l
envs Γ l (removeAll r l') = envs Γ l l'
by (simp add: envs_def list_minus_removeAll_irr)
lemma envs_removeAll2:
r ∈ set l'
envs Γ (removeAll r l) (removeAll r l') = envs Γ l l'
by (simp add: envs_def list_minus_removeAll2)
lemma envs_app:
disjoint (set x) (set z)
envs Γ (x @ z) (y @ z) = envs Γ x y
disjoint (set z) (set x)
envs Γ (z @ x) (z @ y) = envs Γ x y
by (simp_all add: envs_def list_minus_appl list_minus_appr)
Free variables and substitutions
primrec
fvA :: assn ⇒ var set
where
fvA (Aemp) = {}
| fvA (Apure B) = fvB B
| fvA (Apsto k e1 e2) = (fvE e1 ∪ fvE e2)
| fvA (P ** Q) = (fvA P ∪ fvA Q)
| fvA (Awand P Q) = (fvA P ∪ fvA Q)
| fvA (Aconj P Q) = (fvA P ∪ fvA Q)
| fvA (Adisj P Q) = (fvA P ∪ fvA Q)
| fvA (Aex P) = (
⋃x. fvA (P x))
definition
fvAs :: (
'a ⇒ assn) ⇒ var set
where
fvAs Γ = (
⋃x. fvA (Γ x))
primrec
subA :: var ⇒ exp ⇒ assn ⇒ assn
where
subA x E (Aemp) = Aemp
| subA x E (Apure B) = Apure (subB x E B)
| subA x E (Apsto k e1 e2) = (Apsto k (subE x E e1) (subE x E e2))
| subA x E (P ** Q) = (subA x E P ** subA x E Q)
| subA x E (Awand P Q) = Awand (subA x E P) (subA x E Q)
| subA x E (Aconj P Q) = Aconj (subA x E P) (subA x E Q)
| subA x E (Adisj P Q) = Adisj (subA x E P) (subA x E Q)
| subA x E (Aex PP) = Aex (λn. subA x E (PP n))
lemma subAptsto[simp]:
subA x E (e1 ⟼ e2) = (subE x E e1 ⟼ subE x E e2)
by (simp add: Aptsto_def)
lemma subA_assign:
(s,h) ⊨ subA x E P ⟷ (s(x := edenot E s), h) ⊨ P
by (induct P arbitrary: h, simp_all add: subE_assign subB_assign fun_upd_def)
lemma fvA_istar[simp]:
fvA (Aistar Ps) = (⋃P ∈ set Ps. fvA P)
by (induct Ps, simp_all)
Proposition 4.2 for assertions
lemma assn_agrees:
agrees (fvA P) s s'
(s, h) ⊨ P ⟷ (s', h) ⊨ P
apply (induct P arbitrary: h, simp_all add: bexp_agrees)
apply (clarsimp, (subst exp_agrees, simp_all)+ )
apply (rule iff_exI, simp add: agrees_def)
done
Corollaries of Proposition 4.2, useful for automation.
lemma assns_agrees:
agrees (fvAs J) s s'
(s, h) ⊨ envs J l1 l2 ⟷ (s', h) ⊨ envs J l1 l2
apply (clarsimp simp add: envs_def, subst assn_agrees, simp_all)
apply (erule agrees_search, auto simp add: fvAs_def)
done
corollary assns_agreesE[elim]:
(s, h) ⊨ envs J l1 l2 ; agrees (fvAs J) s s'
(s',h) ⊨ envs J l1 l2
by (simp add: assns_agrees)
corollary assn_agrees2[simp]:
x ∉ fvA P
(s(x := v), h) ⊨ P ⟷ (s, h) ⊨ P
by (rule assn_agrees, simp add: agrees_def)
corollary assns_agrees2[simp]:
x ∉ fvAs J
(s(x := v), h) ⊨ envs J l l' ⟷ (s, h) ⊨ envs J l l'
by (rule assns_agrees, simp add: agrees_def)
Meaning of CSL judgments
Definition 5.1: Configuration safety.
primrec
safe :: nat ⇒ cmd ⇒ stack ⇒ pheap ⇒ (rname ⇒ assn) ⇒ assn ⇒ bool
where
safe 0 C s h Γ Q = True
| safe (Suc n) C s h Γ Q = (
(C = Cskip ⟶ (s, h) ⊨ Q)
∧ (∀hF hh. ptoheap (Some h ⊕ hF) hh ⟶ ¬ aborts C (s, hh))
∧ accesses C s ⊆ dom h
∧ writes C s ⊆ fpdom h
∧ (∀hJ hF hh C' σ'.
red C (s, hh) C' σ'
⟶ ptoheap (Some h ⊕ Some hJ ⊕ hF) hh
⟶ (s, hJ) ⊨ envs Γ (llocked C') (llocked C)
⟶ (∃h' hJ'.
ptoheap (Some h' ⊕ Some hJ' ⊕ hF) (snd σ')
∧ (fst σ', hJ') ⊨ envs Γ (llocked C) (llocked C')
∧ safe n C' (fst σ') h' Γ Q)))
The predicate safe n C s h Γ Q says that the command C and the logical state
(s, h) are safe with respect to the resource environment Γ and the
postcondition Q for n execution steps.
Intuitively, any configuration is safe for zero steps.
For n + 1 steps, it must
(i) satisfy the postcondition if it is a terminal configuration,
(ii) not abort,
(iii) access memory only inside its footprint, and
(iv) after any step it does, re-establish the resource invariant and be safe for
another n steps.
Definition 5.2: The meaning of CSL judgements.
definition
CSL :: (rname ⇒ assn) ⇒ assn ⇒ cmd ⇒ assn ⇒ bool
(_ ⊢ { _ } _ { _ })
where
Γ ⊢ {P} C {Q} ≜ (user_cmd C ∧ (∀n s h. (s, h) ⊨ P ⟶ safe n C s h Γ Q))
Basic properties of Definition 5.1
Proposition 4.3: Monotonicity with respect to the step number.
lemma safe_mon:
safe n C s h J Q; m ≤ n
safe m C s h J Q
apply (induct m arbitrary: C s n h l, simp)
apply (case_tac n, clarify)
apply (simp only: safe.simps, clarsimp)
apply (drule all5D, drule (2) all_imp2D, clarsimp)
apply (rule_tac x=h' in exI, rule_tac x=hJ' in exI, simp)
done
Proposition 4.4: Safety depends only the free variables
of C, Q, and Γ.
lemma safe_agrees:
safe n C s h Γ Q ;
agrees (fvC C ∪ fvA Q ∪ fvAs Γ) s s'
safe n C s' h Γ Q
apply (induct n arbitrary: C s s' h bl, simp, simp only: safe.simps, clarify)
apply (rule conjI, clarsimp, subst assn_agrees, subst agreesC, assumption+)
apply (rule conjI, clarsimp)
apply (drule_tac aborts_agrees, simp, fast, simp, simp)
apply (rule conjI, subst (asm) accesses_agrees, simp_all)
apply (rule conjI, subst (asm) writes_agrees, simp_all)
apply (clarify, drule_tac X=fvC C ∪ fvAs Γ ∪ fvA Q in red_agrees,
simp (no_asm), fast, simp (no_asm), fast, clarify)
apply (drule allD, drule (1) all5_impD, clarsimp)
apply (drule imp2D, erule_tac[2] assns_agreesE, simp_all add: agreesC, clarify)
apply (rule_tac x=h'a and y=hJ' in ex2I, simp add: pa_ac)
apply (rule conjI, erule assns_agreesE, subst agreesC, assumption)
apply (erule (1) mall4_imp2D, simp add: agreesC)
apply (drule red_properties, auto)
done
Soundness of the proof rules
Skip
lemma safe_skip[intro!]:
(s,h) ⊨ Q
safe n Cskip s h J Q
by (induct n, simp_all)
theorem rule_skip:
by (auto simp add: CSL_def)
Parallel composition
lemma disj_conv:
pdisj h1 h2
disjoint (fpdom h1) (dom h2)
pdisj h1 h2
disjoint (dom h1) (fpdom h2)
by (simp add: fpdom_def pdisj_def disjoint_def, rule set_eqI, drule_tac a=x in allD, clarsimp)+
lemma safe_par:
safe n C1 s h1 J Q1; safe n C2 s h2 J Q2;
wf_cmd (Cpar C1 C2);
pdisj h1 h2;
disjoint (fvC C1 ∪ fvA Q1 ∪ fvAs J) (wrC C2);
disjoint (fvC C2 ∪ fvA Q2 ∪ fvAs J) (wrC C1)
safe n (Cpar C1 C2) s (padd h1 h2) J (Q1 ** Q2)
apply (induct n arbitrary: C1 C2 s h1 h2 bl1 bl2, simp, clarsimp)
apply (rule conjI, clarify)
— no aborts
apply (erule aborts.cases, simp_all add: pa_ac)
apply (clarify, drule_tac a=Some h2 ⊕ hF in all2_impD, simp add: pa_ac, clarsimp)
apply (clarify, drule_tac a=Some h1 ⊕ hF in all2_impD, simp add: pa_ac, clarsimp)
— no races
apply (clarsimp, erule notE, (erule disjoint_search [rotated])+, erule disj_conv)+
— accesses
apply (rule conjI, erule order_trans, simp)+
apply (rule conjI, erule order_trans, erule fpdom_padd)+
— step
apply (clarsimp, erule red_par_cases, simp_all)
— C1 does a step
apply (clarify, drule_tac a=hJ
and b=Some h2 ⊕ hF in all2D, drule all4_impD,
simp_all add: envs_app locked_eq, clarsimp simp add: pa_ac)
apply (subgoal_tac pdisj h' h2, erule_tac[2] pdisj_search)
apply (rule_tac x=padd h' h2
and y=hJ' in ex2I, simp add: pa_ac)
apply (frule (1) red_wf_cmd, drule red_properties, clarsimp)
apply (drule_tac a=C1'
and b=C2 in mall2D, simp add: hsimps)
apply (drule mall3_imp2D, erule_tac[3] mimp3D, simp_all add: hsimps)
apply (rule_tac s=s in safe_agrees)
apply (rule_tac n=Suc n in safe_mon, simp add: pa_ac, simp)
apply (fastforce simp add: agreesC disjoint_commute)
apply (intro conjI | erule (1) disjoint_search)+
— C2 does a step
apply (clarify, drule_tac a=hJ
and b=Some h1 ⊕ hF in all2D, drule all4_imp2D,
simp_all add: hsimps envs_app pa_ac, clarsimp)
apply (subgoal_tac pdisj h1 h', erule_tac[2] pdisj_search)
apply (rule_tac x=padd h1 h'
and y=hJ' in ex2I, simp add: pa_ac)
apply (frule (1) red_wf_cmd, drule red_properties, clarsimp)
apply (drule_tac a=C1
and b=C2' in mall2D, simp add: hsimps)
apply (drule mall3_imp2D, erule_tac[3] mimp3D, simp_all add: hsimps)
apply (rule_tac s=s in safe_agrees)
apply (rule_tac n=Suc n in safe_mon, simp add: pa_ac, simp)
apply (subst agreesC, bestsimp, bestsimp, bestsimp)
— Par skip skip
apply (clarify)
apply (rule_tac x=padd h1 h2
and y=hJ in ex2I, simp add: pa_ac)
apply (rule_tac safe_skip, simp, (rule exI, erule conjI)+, simp)
done
theorem rule_par:
Γ ⊢ {P1} C1 {Q1} ; Γ ⊢ {P2} C2 {Q2};
disjoint (fvC C1 ∪ fvA Q1 ∪ fvAs Γ) (wrC C2);
disjoint (fvC C2 ∪ fvA Q2 ∪ fvAs Γ) (wrC C1)
Γ ⊢ {P1 ** P2} (Cpar C1 C2) {Q1 ** Q2}
by (auto simp add: CSL_def intro!: safe_par)
Resource declaration
lemma safe_resource:
safe n C s h (Γ(r := R)) Q; wf_cmd C; disjoint (fvA R) (wrC C)
(∀hR. r ∉ locked C ⟶ pdisj h hR ⟶ (s,hR) ⊨ R ⟶ safe n (Cresource r C) s (padd h hR) Γ (Q ** R))
∧ (r ∈ locked C ⟶ safe n (Cresource r C) s h Γ (Q ** R))
apply (induct n arbitrary: C s h, simp, clarsimp simp add: pa_ac)
apply (rule conjI, clarify)
apply (rule conjI, clarify)
— no aborts
apply (erule aborts.cases, simp_all, clarsimp)
apply (drule_tac a=Some hR ⊕ hF in all2_impD, simp add: pa_ac, simp)
— accesses
apply (rule conjI, erule order_trans, simp)
apply (rule conjI, erule order_trans, erule fpdom_padd)
— step
apply (clarify, frule red_properties, clarsimp)
apply (erule red.cases, simp_all, clarsimp, rename_tac C s hh C' s' hh')
— normal step
apply (subgoal_tac pdisj hR hJ, erule_tac[2] pdisj_search)
apply (case_tac r ∈ set (llocked C'), simp_all add: locked_eq)
apply (drule_tac a=padd hJ hR
and b=hF
and c=hh in all3D,
drule_tac a=C'
and b=s'
and c=hh' in all3D, simp_all add: pa_ac)
apply (drule impD, subst sat_envs_expand [
where r=r], simp_all)
apply (rule wf_cmd_distinct_locked, erule (1) red_wf_cmd)
apply (intro exI conjI, simp, simp_all add: envs_upd)
apply (clarsimp simp add: envs_removeAll_irr)
apply (drule (1) mall3_imp2D, erule (1) red_wf_cmd)
apply (drule mimpD, fast, clarsimp)
apply (intro exI conjI, simp+)
— r ∉ locked C'
apply (drule_tac a=hJ
and b=Some hR ⊕ hF
and c=hh in all3D, drule_tac a=C'
and b=s'
and c=hh' in all3D,
simp add: pa_ac)
apply (clarsimp simp add: envs_upd)
apply (drule (1) mall3_imp2D, erule (1) red_wf_cmd)
apply (drule mimpD, fast, clarsimp)
apply (subgoal_tac pdisj h' hR, erule_tac[2] pdisj_search)
apply (rule_tac x=padd h' hR
and y=hJ' in ex2I, simp add: pa_ac)
apply (drule_tac a=hR in all_imp2D, simp_all add: hsimps)
apply (subst assn_agrees, simp_all, fastforce)
— skip
apply (clarsimp simp add: envs_def)
apply (rule_tac x=padd h hR in exI, simp add: pa_ac, rule safe_skip, simp, fast)
— not user cmd
apply (clarsimp)
apply (rule conjI, clarsimp, erule aborts.cases, simp_all, clarsimp, clarsimp)
apply (frule red_properties, clarsimp)
apply (erule red.cases, simp_all, clarsimp, rename_tac C s hh C' s' hh')
apply (drule_tac a=hJ
and b=hF
and c=hh in all3D, drule_tac a=C'
and b=s'
and c=hh' in all3D,
simp add: pa_ac)
apply (clarsimp simp add: envs_upd envs_removeAll2)
apply (drule (1) mall3_imp2D, erule (1) red_wf_cmd)
apply (drule mimpD, fast, clarsimp)
apply (case_tac r ∈ set (llocked C'), simp_all add: locked_eq envs_removeAll2 envs_upd)
apply (intro exI conjI, simp+)
apply (subst (asm) sat_envs_expand [
where r=r], simp_all add: wf_cmd_distinct_locked,
clarsimp simp add: pa_ac, rename_tac hR' hJ')
apply (subgoal_tac pdisj h' hR', erule_tac[2] pdisj_search)
apply (drule (2) all_imp2D, rule_tac x=padd h' hR'
and y=hJ' in ex2I, simp add: pa_ac envs_upd)
done
theorem rule_resource:
Γ(r := R) ⊢ {P} C {Q} ; disjoint (fvA R) (wrC C)
Γ ⊢ {P ** R} (Cresource r C) {Q ** R}
by (clarsimp simp add: CSL_def, drule (1) all3_impD)
(auto simp add: locked_eq dest!: safe_resource)
Frame rule
The safety of the frame rule can be seen as a special case of the parallel composition
rule taking one thread to be the empty command.
lemma safe_frame:
safe n C s h J Q;
pdisj h hR;
disjoint (fvA R) (wrC C);
(s,hR) ⊨ R
safe n C s (padd h hR) J (Q ** R)
apply (induct n arbitrary: C s h hR, simp, clarsimp simp add: pa_ac)
apply (rule conjI, clarify, fast)
apply (rule conjI, clarify)
— no aborts
apply (drule_tac a=Some hR ⊕ hF in all2_impD, simp add: pa_ac, simp)
— accesses
apply (rule conjI, erule order_trans, simp)
apply (rule conjI, erule order_trans, erule fpdom_padd)
— step
apply (clarify, frule red_properties, clarsimp)
apply (drule_tac a=hJ
and b=Some hR ⊕ hF in all3D, simp add: pa_ac, drule (1) all3_impD, clarsimp)
apply (subgoal_tac pdisj h' hR, erule_tac[2] pdisj_search)
apply (rule_tac y=hJ'
and x=padd h' hR in ex2I, clarsimp simp add: pa_ac)
apply (drule mall4D, erule mimp4D, simp_all add: hsimps)
apply (erule (1) disjoint_search)
apply (subst assn_agrees, simp_all, fastforce)
done
theorem rule_frame:
Γ ⊢ {P} C {Q} ; disjoint (fvA R) (wrC C)
Γ ⊢ {P ** R} C {Q ** R}
by (auto simp add: CSL_def intro: safe_frame)
Conditional critical regions
lemma safe_inwith:
safe n C s h Γ (Q ** Γ r); wf_cmd (Cinwith r C)
safe n (Cinwith r C) s h Γ Q
apply (induct n arbitrary: C s h, simp_all, clarify)
apply (rule conjI)
apply (clarify, erule aborts.cases, simp_all, clarsimp)
apply (clarify, erule_tac red.cases, simp_all, clarify)
apply (frule (1) red_wf_cmd)
apply (drule allD, drule (1) all5_imp2D, simp_all)
apply (simp add: envs_def list_minus_removeAll [THEN sym] locked_eq)+
apply fast
apply (clarsimp simp add: envs_def, rename_tac hQ hJ)
apply (rule_tac x=hQ
and y=hJ in ex2I, simp add: pa_ac, fast)
done
theorem rule_with:
Γ ⊢ {Aconj (P ** Γ r) (Apure B)} C {Q ** Γ r}
Γ ⊢ {P} Cwith r B C {Q}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp)
apply (rule conjI, clarify, erule aborts.cases, simp_all)
apply (clarify, erule red.cases, simp_all, clarsimp)
apply (subgoal_tac pdisj h hJ, erule_tac[2] pdisj_search)
apply (simp add: envs_def, rule_tac x=padd h hJ in exI, simp add: pa_ac)
apply (rule safe_inwith, erule all3_impD, auto dest: user_cmdD)
done
Sequential composition
lemma safe_seq:
safe n C s h J Q; user_cmd C2;
∀m s' h'. m ≤ n ∧ (s', h') ⊨ Q ⟶ safe m C2 s' h' J R
safe n (Cseq C C2) s h J R
apply (induct n arbitrary: C s h l, simp, clarsimp)
apply (rule conjI, clarsimp)
apply (erule aborts.cases, simp_all, clarsimp)
apply (clarsimp, erule red.cases, simp_all)
— Seq1
apply (clarify, rule_tac x=h
and y=hJ in ex2I, simp)
— Seq2
apply (clarify, drule all3D, drule (2) all3_imp2D, clarsimp)
apply (drule (1) mall3_impD, rule_tac x=h'
and y=hJ' in ex2I, simp)
done
theorem rule_seq:
Γ ⊢ {P} C1 {Q} ; Γ ⊢ {Q} C2 {R}
Γ ⊢ {P} Cseq C1 C2 {R}
by (auto simp add: CSL_def intro!: safe_seq)
Conditionals (if-then-else)
theorem rule_if:
Γ ⊢ {Aconj P (Apure B)} C1 {Q} ;
Γ ⊢ {Aconj P (Apure (Bnot B))} C2 {Q}
Γ ⊢ {P} Cif B C1 C2 {Q}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp)
apply (intro conjI allI impI notI, erule aborts.cases, simp_all)
apply (erule red.cases, simp_all)
apply (clarsimp, intro exI, (rule conjI, simp)+, simp)+
done
While
lemma safe_while:
Γ ⊢ {Aconj P (Apure B)} C {P} ; (s, h) ⊨ P
safe n (Cwhile B C) s h Γ (Aconj P (Apure (Bnot B)))
apply (induct n arbitrary: s h, simp, clarsimp)
apply (intro conjI allI impI notI, erule aborts.cases, simp_all)
apply (erule red.cases, simp_all)
apply (clarsimp, intro exI, (rule conjI, simp)+)
apply (subgoal_tac ∀m s h. m ≤ n ∧ (s, h) ⊨ P ⟶ safe m (Cwhile B C) s h Γ (Aconj P (Apure (Bnot B))))
apply (case_tac n, simp, clarsimp)
apply (intro conjI allI impI notI, erule aborts.cases, simp_all)
apply (erule red.cases, simp_all)
apply (clarsimp, intro exI, (rule conjI, simp)+)
apply (clarsimp simp add: CSL_def, rule safe_seq, blast, simp, clarsimp)
apply (clarsimp, intro exI, (rule conjI, simp)+, rule safe_skip, simp)
apply (clarsimp, drule (1) mall2_impD, erule (1) safe_mon)
done
theorem rule_while:
Γ ⊢ {Aconj P (Apure B)} C {P}
Γ ⊢ {P} Cwhile B C {Aconj P (Apure (Bnot B))}
by (auto simp add: CSL_def intro: safe_while)
Local variable declaration
lemma safe_inlocal:
safe n C (s(x:=v)) h Γ Q ; x ∉ fvA Q ∪ fvAs Γ
safe n (Cinlocal x v C) s h Γ Q
apply (induct n arbitrary: s h v C, simp, clarsimp)
apply (intro conjI allI impI notI, erule aborts.cases, simp_all, clarsimp)
apply (erule red.cases, simp_all)
apply (clarsimp, drule allD, drule (1) all5_imp2D, simp)
apply (clarsimp, intro exI, (rule conjI, simp)+, simp)
apply (fastforce simp add: safe_skip)
done
theorem rule_local:
Γ ⊢ {Aconj P (Apure (Beq (Evar x) E))} C {Q} ;
x ∉ fvA P ∪ fvA Q ∪ fvAs Γ ∪ fvE E
Γ ⊢ {P} Clocal x E C {Q}
apply (auto simp add: CSL_def intro: safe_inlocal)
apply (case_tac n, simp_all)
apply (intro conjI allI impI notI, erule aborts.cases, simp_all)
apply (erule red.cases, simp_all, clarsimp)
apply (intro exI conjI, simp_all, rule safe_inlocal, simp_all)
done
Basic commands (Assign, Read, Write, Alloc, Free)
theorem rule_assign:
x ∉ fvAs Γ
Γ ⊢ {subA x E Q} Cassign x E {Q}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp)
apply (rule conjI, clarsimp, erule aborts.cases, simp_all)
apply (clarsimp, erule red.cases, simp_all)
apply (rule_tac x=h in exI, rule_tac x=hJ in exI,
clarsimp simp add: subA_assign)
done
lemma ptoheap_read:
ptoheap (Some h ⊕ hF) hh; h x = Some (v, k)
hh x = Some v
apply (case_tac hF, (simp add: ptoheap_def mypadd_def split: if_split_asm)+)
apply (drule_tac a=x in allD, fastforce simp add: padd_def split: option.splits)
done
theorem rule_read:
x ∉ fvE E ∪ fvE E' ∪ fvAs Γ
Γ ⊢ {Apsto k E E'} Cread x E {Aconj (Apsto k E E') (Apure (Beq (Evar x) E'))}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp, intro conjI allI impI notI)
apply (erule aborts.cases, simp_all, fastforce dest: ptoheap_read)
apply (erule red.cases, simp_all, fastforce dest: ptoheap_read)
done
lemma pdisj_upd2:
h x = Some (w, pfull)
pdisj (h(x ↦ (v, pfull))) h' = pdisj h h'
by (simp add: pdisj_def, rule iff_allI, auto split: option.splits)
lemma write_helper:
ptoheap (Some h ⊕ hF) hh; h x = Some (v, pfull)
ptoheap (Some (h(x↦ (w, pfull))) ⊕ hF) (hh(x↦w))
apply (case_tac hF, simp_all add: ptoheap_def mypadd_def split: if_split_asm)
apply (clarsimp simp add: pdisj_upd2, simp add: pdisj_def, (drule_tac a=xa in allD)+)
apply (clarsimp simp add: pdisj_def padd_def split: option.splits)
done
theorem rule_write:
Γ ⊢ {E ⟼ E0} Cwrite E E' {E ⟼ E'}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp simp add: fpdom_def, intro conjI allI impI notI)
apply (erule aborts.cases, simp_all, fastforce dest: ptoheap_read)
apply (erule red.cases, simp_all, fastforce elim: write_helper)
done
lemma alloc_helper:
ptoheap h hh; x ∉ dom hh
ptoheap (Some [x ↦ (v, pfull)] ⊕ h) (hh(x ↦ v))
apply (auto simp add: ptoheap_def mypadd_def pdisj_def padd_def split: option.splits)
apply (drule_tac a=xa in allD, simp)
done
theorem rule_alloc:
x ∉ fvE E ∪ fvAs Γ
Γ ⊢ {Aemp} Calloc x E {Evar x ⟼ E}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp, intro conjI allI impI notI)
apply (erule aborts.cases, simp_all)
apply (erule red.cases, simp_all, fastforce elim: alloc_helper)
done
lemma free_helper:
ptoheap (Some h ⊕ hF) hh; h x = Some (v, pfull)
ptoheap (Some (h(x:=None)) ⊕ hF) (hh(x:=None))
apply (case_tac hF, simp_all add: ptoheap_def mypadd_def split: if_split_asm)
apply (clarsimp simp add: pdisj_def, (drule_tac a=xa in allD)+)
apply (clarsimp simp add: padd_def split: option.splits)
done
theorem rule_free:
Γ ⊢ {E ⟼ E0} Cdispose E {Aemp}
apply (clarsimp simp add: CSL_def)
apply (case_tac n, simp, clarsimp simp add: fpdom_def, intro conjI allI impI notI)
apply (erule aborts.cases, simp_all, fastforce dest: ptoheap_read)
apply (erule red.cases, simp_all, fastforce elim: free_helper dom_eqD)
done
Simple structural rules (Conseq, Disj, Ex)
lemma safe_conseq:
safe n C s h Γ Q ; Q ⊑ Q'
safe n C s h Γ Q'
apply (induct n arbitrary: C s h, simp, clarsimp simp add: implies_def)
apply (drule allD, drule (2) all5_imp2D, simp_all, clarsimp)
apply (drule (1) mall3_impD, rule_tac x=h'
and y=hJ' in ex2I, simp)
done
theorem rule_conseq:
Γ ⊢ {P} C {Q} ; P' ⊑ P ; Q ⊑ Q'
Γ ⊢ {P'} C {Q'}
by (fastforce simp add: CSL_def implies_def elim!: safe_conseq)
theorem rule_disj:
Γ ⊢ {P1} C {Q1}; Γ ⊢ {P2} C {Q2}
Γ ⊢ {Adisj P1 P2} C {Adisj Q1 Q2}
by (clarsimp simp add: CSL_def, safe)
(rule safe_conseq, simp_all add: implies_def, drule (2) all3_impD, force)+
theorem rule_ex:
∀n. (Γ ⊢ {P n} C {Q n})
Γ ⊢ {Aex P} C {Aex Q}
by (clarsimp simp add: CSL_def, rule_tac Q = Q v in safe_conseq,
auto simp add: implies_def)
Conjunction rule
lemma safe_conj:
safe n C s h Γ Q1;
safe n C s h Γ Q2;
∀r. precise (Γ r)
safe n C s h Γ (Aconj Q1 Q2)
apply (induct n arbitrary: C s h, simp, clarsimp)
apply (drule allD, drule (2) all5_imp2D, clarsimp)+
apply (rule_tac x=h'
and y=hJ' in ex2I, simp)
apply (erule mall3_imp2D, simp_all)
apply (subgoal_tac Some hJ' ⊕ Some h' = Some hJ'a ⊕ Some h'a)
apply (subst (asm) (8 9) mypadd_def, simp split: if_split_asm)
apply (erule_tac[2] notE, erule_tac[2] pdisj_search)
apply (drule_tac s=a
and y=h'
and y'=h'a in preciseD [rotated], simp_all
add: envs_def precise_istar, fast)
apply (case_tac hF, simp add: ptoheap_def, clarsimp, rename_tac hR)
apply (drule (1) ptoD, rule_tac x=Some hR in pa_cancel, simp add: pa_ac)
apply (rule notI, simp add: pa_ac ptoheap_def)
done
theorem rule_conj:
Γ ⊢ {P1} C {Q1};
Γ ⊢ {P2} C {Q2};
∀r. precise (Γ r)
Γ ⊢ {Aconj P1 P2} C {Aconj Q1 Q2}
by (auto simp add: CSL_def intro: safe_conj)
Auxiliary variables
lemma safe_aux:
safe n C s h Γ Q; disjoint X (fvC (rem_vars X C) ∪ fvA Q ∪ fvAs Γ)
safe n (rem_vars X C) s h Γ Q
apply (induct n arbitrary: C s h, simp_all)
apply (intro conjI impI allI, clarsimp)
apply (fastforce intro: aborts_remvars)
apply (elim conjE, erule order_trans [OF accesses_remvars])
apply (clarsimp, frule red_properties, drule aux_red, simp_all)
apply (drule_tac a=Some hJ ⊕ hF in allD, simp add: pa_ac)
apply (clarsimp, drule allD, drule (2) all5_imp2D, clarsimp)
apply (intro exI conjI, simp+)
apply (fastforce simp add: disjoint_commute agreesC)
apply (drule (1) mall3_imp2D, fast)
apply (erule safe_agrees, fastforce simp add: disjoint_commute agreesC)
done
The proof rule for eliminating auxiliary variables. Note that a
set of variables, X, is auxiliary for a command C
iff it disjoint from fvC (rem_vars X C).
theorem rule_aux:
Γ ⊢ {P} C {Q} ;
disjoint X (fvA P ∪ fvA Q ∪ fvAs Γ ∪ fvC (rem_vars X C))
Γ ⊢ {P} rem_vars X C {Q}
by (auto simp add: CSL_def safe_aux disjoint_commute)
end