Theory Constructions
theory Constructions
imports
Safety_Logic
begin
section‹ Constructions in the ∗‹('a, 's, 'v) spec› lattice\label{sec:constructions} ›
subsection‹ Constrains-at-most \label{sec:cam} ›
text‹
\<^citet>‹‹\S3.1› in "AbadiPlotkin:1993"›
require that processes to be composed in parallel
∗‹constrain at most› (CAM) distinct sets of agents:
intuitively each process cannot block other processes from taking
steps after any of its transitions. We model this as a closure.
See \S\ref{sec:abadi_plotkin} for a discussion of their composition rules.
Observations:
▪ the sense of the relation ‹r› here is inverted wrt Abadi/Plotkin
▪ this is a key ingredient in interference closure (\S\ref{sec:interference_closure})
▪ this closure is antimatroidal
›
setup ‹Sign.mandatory_path "spec"›
setup ‹Sign.mandatory_path "cam"›
definition cl :: "('a, 's) steps ⇒ ('a, 's, 'v) spec ⇒ ('a, 's, 'v) spec" where
"cl r P = P ⊔ spec.term.none (spec.term.all P ⤜ (λ_::unit. spec.rel r :: (_, _, unit) spec))"
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "term"›
setup ‹Sign.mandatory_path "none.cam"›
lemma cl:
shows "spec.term.none (spec.cam.cl r P) = spec.cam.cl r (spec.term.none P)"
by (simp add: spec.cam.cl_def spec.bind.supL spec.bind.bind spec.term.all.bind ac_simps
flip: spec.bind.botR bot_fun_def)
lemma cl_rel_wind:
fixes P :: "('a, 's, 'v) spec"
shows "spec.cam.cl r P ⪢ spec.term.none (spec.rel r :: ('a, 's, 'w) spec)
= spec.term.none (spec.cam.cl r P)"
by (simp add: spec.cam.cl_def spec.term.none.sup spec.term.none.bind spec.bind.supL spec.bind.bind
bot_fun_def sup.absorb2
spec.vmap.unitL[where f=P] spec.vmap.unitL[where f="spec.term.all P"]
spec.vmap.unitL[where f="spec.rel r :: ('a, 's, 'w) spec"]
spec.term.all.vmap_unit spec.vmap.unit_rel spec.bind.mono spec.term.all.expansive
flip: spec.bind.botR)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "all.cam"›
lemma cl_le:
shows "spec.cam.cl r (spec.term.all P) ≤ spec.term.all (spec.cam.cl r P)"
by (simp add: spec.term.none.cam.cl flip: spec.term.galois) (simp flip: spec.term.none.cam.cl)
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
interpretation cam: closure_complete_distrib_lattice_distributive_class "spec.cam.cl r" for r :: "('a, 's) steps"
proof standard
show "P ≤ spec.cam.cl r Q ⟷ spec.cam.cl r P ≤ spec.cam.cl r Q" (is "?lhs ⟷ ?rhs") for P Q :: "('a, 's, 'v) spec"
proof(rule iffI)
assume ?lhs show ?rhs
apply (subst spec.cam.cl_def)
apply (strengthen ord_to_strengthen(1)[OF ‹?lhs›])
apply (simp add: spec.cam.cl_def spec.term.galois spec.term.all.sup spec.term.all.bind
spec.bind.supL spec.term.all.rel spec.bind.bind spec.rel.wind_bind)
done
next
show "?rhs ⟹ ?lhs"
by (simp add: spec.cam.cl_def)
qed
show "spec.cam.cl r (⨆P) ≤ ⨆(spec.cam.cl r ` P) ⊔ spec.cam.cl r ⊥" for P :: "('a, 's, 'v) spec set"
by (simp add: spec.cam.cl_def spec.term.none.bind spec.term.all.Sup spec.bind.SupL
spec.term.none.Sup SUP_upper2)
qed
setup ‹Sign.mandatory_path "cam"›
setup ‹Sign.mandatory_path "cl"›
lemma bot[simp]:
shows "spec.cam.cl r ⊥ = ⊥"
by (simp add: spec.cam.cl_def)
lemma mono:
fixes r :: "('a, 's) steps"
assumes "r ⊆ r'"
assumes "P ≤ P'"
shows "spec.cam.cl r P ≤ spec.cam.cl r' P'"
unfolding spec.cam.cl_def
apply (strengthen ord_to_strengthen(1)[OF ‹r ≤ r'›])
apply (strengthen ord_to_strengthen(1)[OF ‹P ≤ P'›])
apply blast
done
declare spec.cam.strengthen_cl[strg del]
lemma strengthen[strg]:
assumes "st_ord F r r'"
assumes "st_ord F P P'"
shows "st_ord F (spec.cam.cl r P) (spec.cam.cl r' P')"
using assms by (cases F; simp add: spec.cam.cl.mono)
lemma Sup:
shows "spec.cam.cl r (⨆X) = (⨆P∈X. spec.cam.cl r P)"
by (simp add: spec.cam.cl_Sup)
lemmas sup = spec.cam.cl.Sup[where X="{P, Q}" for P Q, simplified]
lemma rel_empty:
shows "spec.cam.cl {} P = P"
by (simp add: spec.cam.cl_def spec.rel.empty sup.absorb1 UNIV_unit)
lemma rel_reflcl:
shows "spec.cam.cl (r ∪ A × Id) P = spec.cam.cl r P"
and "spec.cam.cl (A × Id ∪ r) P = spec.cam.cl r P"
by (simp_all add: spec.cam.cl_def spec.rel.reflcl)
lemma rel_minus_Id:
shows "spec.cam.cl (r - UNIV × Id) P = spec.cam.cl r P"
by (metis Un_Diff_cancel2 spec.cam.cl.rel_reflcl(1))
lemma Inf:
shows "spec.cam.cl r (⨅X) = ⨅(spec.cam.cl r ` X)" (is "?lhs = ?rhs")
proof(rule antisym[OF spec.cam.cl_Inf_le spec.singleton_le_extI])
show "⦉σ⦊ ≤ ?lhs" if "⦉σ⦊ ≤ ?rhs" for σ
proof (cases "trace.term σ")
case None
have "⦉σ⦊ ≤ ⨅ (spec.term.all ` X) ⤜ (λv. spec.term.none (spec.rel r))"
if "x ∈ X" and "¬ ⦉σ⦊ ≤ x"
for x
proof -
from ‹⦉σ⦊ ≤ ?rhs› that
have "⦉σ⦊ ≤ spec.term.all x ⤜ (λ_::unit. spec.term.none (spec.rel r :: (_, _, unit) spec))"
by (auto simp: spec.cam.cl_def le_Inf_iff spec.term.none.bind)
then show ?thesis
proof(induct rule: spec.singleton.bind_le)
case incomplete with ‹¬ ⦉σ⦊ ≤ x› show ?case
using order_trans by auto
next
case (continue σ⇩f σ⇩g v⇩f)
from None obtain xs ys
where *: "∀xs' zs. trace.rest σ = xs' @ zs ∧ trace.steps' (trace.final' (trace.init σ) xs') zs ⊆ r
⟶ length xs ≤ length xs'"
"xs @ ys = trace.rest σ"
"trace.steps' (trace.final' (trace.init σ) xs) ys ⊆ r"
using ex_has_least_nat[where P="λxs. ∃ys. trace.rest σ = xs @ ys
∧ trace.steps' (trace.final' (trace.init σ) xs) ys ⊆ r"
and k="trace.rest σ"
and m=length]
by clarsimp
show ?case
proof(induct rule: spec.bind.continueI[where s="trace.init σ" and xs=xs and ys=ys
and v=undefined and w="trace.term σ",
simplified ‹xs @ ys = trace.rest σ› trace.t.collapse,
case_names f g])
case f
have "⦉trace.init σ, xs, None⦊ ≤ x"
if "x ∈ X"
and "⦉σ⦊ ≤ spec.cam.cl r x"
for x
using that(2)[unfolded spec.cam.cl_def, simplified]
proof(induct rule: disjE[consumes 1, case_names expansive cam])
case expansive with ‹xs @ ys = trace.rest σ› show ?case
by (cases σ)
(fastforce elim: order.trans[rotated]
simp: spec.singleton.mono trace.less_eq_same_append_conv)
next
case cam from cam[unfolded spec.term.none.bind] show ?case
proof(induct rule: spec.singleton.bind_le)
case incomplete with ‹xs @ ys = trace.rest σ› show ?case
by clarsimp
(metis prefixI spec.singleton.mono spec.singleton_le_ext_conv
spec.term.none.contractive trace.less_eq_None(2))
next
case (continue σ⇩f σ⇩g v⇩f) with *(1,2) show ?case
by (clarsimp simp: spec.singleton.le_conv trace.less_eq_None
elim!: order.trans[rotated]
intro!: spec.singleton.mono)
(metis prefixI prefix_length_prefix)
qed
qed
with ‹⦉σ⦊ ≤ ?rhs› show ?case
by (simp add: le_Inf_iff spec.singleton.le_conv exI[where x=None])
next
case g with None *(3) show ?case
by (simp add: spec.singleton.le_conv)
qed
qed
qed
then show "⦉σ⦊ ≤ ?lhs"
by (auto simp: spec.cam.cl_def spec.term.none.bind spec.term.all.Inf le_Inf_iff)
next
case Some with ‹⦉σ⦊ ≤ ?rhs› show ?thesis
by (simp add: le_Inf_iff spec.cam.cl_def spec.singleton.term.none_le_conv)
qed
qed
lemmas inf = spec.cam.cl.Inf[where X="{P, Q}" for P Q, simplified]
lemma idle:
shows "spec.cam.cl r spec.idle = spec.term.none (spec.rel r :: (_, _, unit) spec)"
by (simp add: spec.cam.cl_def spec.term.all.idle UNIV_unit spec.bind.returnL
spec.idle_le sup_absorb2)
lemma bind:
shows "spec.cam.cl r (f ⤜ g) = spec.cam.cl r f ⤜ (λv. spec.cam.cl r (g v))"
by (simp add: spec.cam.cl_def spec.bind.supL spec.bind.supR spec.bind.bind ac_simps spec.term.all.bind
flip: spec.bind.botR bot_fun_def)
lemma action:
fixes r :: "('a, 's) steps"
fixes F :: "('v × 'a × 's × 's) set"
shows "spec.cam.cl r (spec.action F)
= spec.action F
⊔ spec.term.none (spec.action F ⪢ (spec.rel r :: (_, _, unit) spec))
⊔ spec.term.none (spec.rel r :: (_, _, unit) spec)"
by (simp add: spec.cam.cl_def spec.term.all.action spec.term.none.bind spec.term.none.sup
spec.bind.botR spec.bind.supL spec.bind.returnL spec.idle_le
spec.vmap.unitL[where f="spec.action F"] spec.map.surj_sf_action
UNIV_unit map_prod_const_image ac_simps
flip: spec.return_def)
lemma return:
shows "spec.cam.cl r (spec.return v) = spec.return v ⊔ spec.term.none (spec.rel r :: (_, _, unit) spec)"
unfolding spec.return_def spec.cam.cl.action
by (simp add: spec.bind.returnL spec.idle_le bot_fun_def
flip: spec.return_def bot_fun_def)
lemma rel_le:
assumes "r ⊆ r' ∨ r' ⊆ r"
shows "spec.cam.cl r (spec.rel r') ≤ spec.rel (r ∪ r')"
using assms
by (auto simp: spec.cam.cl_def spec.rel.mono spec.term.all.rel
spec.rel.wind_bind_leading spec.rel.wind_bind_trailing spec.term.galois)
lemma rel:
assumes "r ⊆ r'"
shows "spec.cam.cl r (spec.rel r') = spec.rel r'"
by (simp add: assms spec.eq_iff spec.cam.expansive
order.trans[OF spec.cam.cl.rel_le[OF disjI1] spec.rel.mono])
lemma inf_rel:
fixes r :: "('a, 's) steps"
fixes s :: "('a, 's) steps"
fixes P :: "('a, 's, 'v) spec"
shows "spec.rel r ⊓ spec.cam.cl r' P = spec.cam.cl (r ∩ r') (spec.rel r ⊓ P)" (is ?thesis1)
and "spec.cam.cl r' P ⊓ spec.rel r = spec.cam.cl (r ∩ r') (spec.rel r ⊓ P)" (is ?thesis2)
proof -
show ?thesis1
by (simp add: spec.cam.cl_def ac_simps inf_sup_distrib
spec.term.none.bind spec.term.all.inf spec.term.all.rel
spec.bind.inf_rel spec.rel.inf spec.term.none.inf spec.term.none.inf_none_rel(1))
then show ?thesis2
by (rule inf_commute_conv)
qed
lemma bind_return:
shows "spec.cam.cl r (f ⪢ spec.return v) = spec.cam.cl r f ⪢ spec.return v"
by (simp add: spec.cam.cl.bind spec.cam.cl.return spec.bind.supR sup.absorb1 spec.term.none.cam.cl_rel_wind)
lemma heyting_le:
shows "spec.cam.cl r (P ❙⟶⇩H Q) ≤ P ❙⟶⇩H spec.cam.cl r Q"
by (force intro!: SupI
dest: spec.cam.mono_cl[where r=r]
elim: order.trans[rotated]
simp: heyting_def spec.cam.cl.Sup spec.cam.cl.inf le_infI1 spec.cam.expansive)
lemma pre:
shows "spec.cam.cl r (spec.pre P) = spec.pre P"
by (simp add: spec.cam.cl_def spec.term.none.bind spec.term.all.pre sup_iff_le spec.bind.inf_pre
flip: inf_iff_le)
lemma post:
shows "spec.cam.cl r (spec.post Q) = spec.post Q"
by (simp add: spec.cam.cl_def spec.term.none.post_le sup_iff_le)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "closed"›
lemma empty:
shows "spec.cam.closed {} = UNIV"
by (simp add: order.eq_iff spec.cam.cl.rel_empty spec.cam.closed_clI subsetI)
lemma antimonotone:
shows "antimono spec.cam.closed"
by (rule monotoneI) (auto intro: spec.cam.closed_clI elim: spec.cam.le_closedE[OF spec.cam.cl.mono])
lemmas strengthen[strg] = st_ord_antimono[OF spec.cam.closed.antimonotone]
lemmas antimono = antimonoD[OF spec.cam.closed.antimonotone, of r r' for r r']
lemma reflcl:
shows "spec.cam.closed (r ∪ A × Id) = spec.cam.closed r"
by (simp add: spec.cam.cl.rel_reflcl(1) spec.cam.closed_def)
setup ‹Sign.mandatory_path "term"›
lemma none:
assumes "P ∈ spec.cam.closed r"
shows "spec.term.none P ∈ spec.cam.closed r"
by (simp add: assms spec.cam.closed_clI flip: spec.term.none.cam.cl spec.cam.closed_conv[OF assms])
setup ‹Sign.parent_path›
lemma bind:
fixes f :: "('a, 's, 'v) spec"
fixes g :: "'v ⇒ ('a, 's, 'w) spec"
assumes "f ∈ spec.cam.closed r"
assumes "⋀x. g x ∈ spec.cam.closed r"
shows "f ⤜ g ∈ spec.cam.closed r"
by (simp add: assms spec.cam.closed_clI spec.cam.least spec.cam.cl.bind spec.bind.mono)
lemma rel[intro]:
assumes "r ⊆ r'"
shows "spec.rel r' ∈ spec.cam.closed r"
by (simp add: assms spec.cam.closed_clI spec.cam.cl.rel)
lemma pre[intro]:
shows "spec.pre P ∈ spec.cam.closed r"
by (simp add: spec.cam.closed_clI spec.cam.cl.pre)
lemma post[intro]:
shows "spec.post Q ∈ spec.cam.closed r"
by (simp add: spec.cam.closed_clI spec.cam.cl.post)
lemma heyting[intro]:
assumes "Q ∈ spec.cam.closed r"
shows "P ❙⟶⇩H Q ∈ spec.cam.closed r"
by (rule spec.cam.closed_clI)
(simp add: assms order.trans[OF spec.cam.cl.heyting_le] flip: spec.cam.closed_conv)
lemma snoc_conv:
fixes P :: "('a, 's, 'v) spec"
assumes "P ∈ spec.cam.closed r"
assumes "(fst x, trace.final' s xs, snd x) ∈ r ∪ UNIV × Id"
shows "⦉s, xs @ [x], None⦊ ≤ P ⟷ ⦉s, xs, None⦊ ≤ P" (is "?lhs ⟷ ?rhs")
proof(rule iffI)
show "?lhs ⟹ ?rhs"
by (erule order.trans[rotated]) (simp add: spec.singleton.mono trace.less_eq_same_append_conv)
from assms(2) show "?rhs ⟹ ?lhs"
by (subst spec.cam.closed_conv[OF ‹P ∈ spec.cam.closed r›])
(auto simp: spec.cam.cl_def spec.singleton.term.none_le_conv
spec.term.none.singleton spec.steps.singleton
simp flip: spec.rel.galois spec.term.galois
intro: spec.bind.continueI)
qed
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "invmap.cam"›
lemma cl:
fixes af :: "'a ⇒ 'b"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
fixes r :: "('b, 't) steps"
fixes P :: "('b, 't, 'w) spec"
shows "spec.invmap af sf vf (spec.cam.cl r P)
= spec.cam.cl (map_prod af (map_prod sf sf) -` (r ∪ UNIV × Id)) (spec.invmap af sf vf P)"
by (simp add: spec.cam.cl_def spec.invmap.sup spec.invmap.bind spec.invmap.rel spec.term.all.invmap
flip: spec.term.none.invmap_gen[where vf=id])
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "map.cam"›
lemma cl_le:
fixes af :: "'a ⇒ 'b"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
fixes r :: "('a, 's) steps"
fixes P :: "('a, 's, 'v) spec"
shows "spec.map af sf vf (spec.cam.cl r P)
≤ spec.cam.cl (map_prod af (map_prod sf sf) ` r) (spec.map af sf vf P)"
by (simp add: spec.map_invmap.galois spec.map_invmap.upper_lower_expansive
spec.invmap.cam.cl spec.cam.cl.mono subset_vimage_iff le_supI1)
lemma cl_inj_sf:
fixes af :: "'a ⇒ 'b"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
fixes r :: "('a, 's) steps"
fixes P :: "('a, 's, 'v) spec"
assumes "inj sf"
shows "spec.map af sf vf (spec.cam.cl r P)
= spec.cam.cl (map_prod af (map_prod sf sf) ` r) (spec.map af sf vf P)"
apply (simp add: spec.cam.cl_def spec.map.sup spec.map.bind_inj_sf[OF ‹inj sf›] spec.term.all.map
flip: spec.term.none.map_gen[where vf=id])
apply (subst spec.map.rel, blast dest: injD[OF ‹inj sf›])
apply (simp add: inf.absorb1 spec.map_invmap.galois spec.invmap.post flip: spec.bind_post_pre)
done
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
subsection‹ Abadi and Plotkin's composition principle\label{sec:abadi_plotkin} ›
text‹
\<^citet>‹"AbadiPlotkin:1991" and "AbadiPlotkin:1993"›
develop a theory of circular reasoning about Heyting implication for
safety properties under the mild condition that each is CAM-closed with respect to the other.
›
setup ‹Sign.mandatory_path "spec"›
abbreviation ap_cam_cl :: "'a set ⇒ ('a, 's, 'v) spec ⇒ ('a, 's, 'v) spec" where
"ap_cam_cl as ≡ spec.cam.cl ((-as) × UNIV)"
abbreviation (input) ap_cam_closed :: "'a set ⇒ ('a, 's, 'v) spec set" where
"ap_cam_closed as ≡ spec.cam.closed ((-as) × UNIV)"
lemma composition_principle_1:
fixes P :: "('a, 's, 'v) spec"
assumes "P ∈ spec.ap_cam_closed as"
assumes "P ∈ spec.term.closed _"
assumes "spec.idle ≤ P"
shows "spec.ap_cam_cl (-as) P ❙⟶⇩H P ≤ P" (is "?lhs ≤ ?rhs")
proof(rule spec.term.closed.singleton_le_extI)
show "⦉s, xs, None⦊ ≤ ?rhs" if "⦉s, xs, None⦊ ≤ ?lhs" for s xs
using that
proof(induct xs rule: rev_induct)
case Nil
from ‹spec.idle ≤ P› show ?case
by (simp add: order.trans[OF spec.idle.minimal_le])
next
case (snoc x xs)
from snoc.prems have "⦉s, xs, None⦊ ≤ spec.ap_cam_cl (- as) P ❙⟶⇩H P"
by (simp add: order.trans[OF spec.singleton.mono, rotated] trace.less_eq_None)
with snoc.hyps have "⦉s, xs, None⦊ ≤ P" by blast
show ?case
proof(cases "fst x ∈ as")
case True
with ‹⦉s, xs, None⦊ ≤ P› have "⦉s, xs @ [x], None⦊ ≤ spec.ap_cam_cl (-as) P"
by (subst spec.cam.closed.snoc_conv) (auto simp: order.trans[OF _ spec.cam.expansive])
with snoc.prems show ?thesis by (blast intro: heyting.mp)
next
case False with ‹P ∈ spec.ap_cam_closed as› ‹⦉s, xs, None⦊ ≤ P› show ?thesis
by (simp add: spec.cam.closed.snoc_conv)
qed
qed
qed fact
lemma composition_principle_half:
assumes "M⇩1 ∈ spec.ap_cam_closed a⇩1"
assumes "M⇩2 ∈ spec.ap_cam_closed a⇩2"
assumes "M⇩1 ∈ spec.term.closed _"
assumes "spec.idle ≤ M⇩1"
assumes "a⇩1 ∩ a⇩2 = {}"
shows "(M⇩1 ❙⟶⇩H M⇩2) ⊓ (M⇩2 ❙⟶⇩H M⇩1) ≤ M⇩1"
proof -
have "(M⇩1 ❙⟶⇩H M⇩2) ⊓ (M⇩2 ❙⟶⇩H M⇩1) ≤ (spec.ap_cam_cl (-a⇩1) M⇩1 ❙⟶⇩H spec.ap_cam_cl (-a⇩1) M⇩2) ⊓ (M⇩2 ❙⟶⇩H M⇩1)"
by (rule inf_mono[OF heyting.closure_imp_distrib_le[OF closure.axioms(2)[OF spec.cam.closure_axioms]] order.refl])
(simp add: spec.cam.cl.inf)
also have "… ≤ spec.ap_cam_cl (-a⇩1) M⇩1 ❙⟶⇩H M⇩1"
proof -
from ‹M⇩2 ∈ spec.ap_cam_closed a⇩2› ‹a⇩1 ∩ a⇩2 = {}› have "spec.ap_cam_cl (-a⇩1) M⇩2 ≤ M⇩2"
by (fastforce intro: spec.cam.least elim: subsetD[OF spec.cam.closed.antimono, rotated])
then show ?thesis
by (simp add: heyting.trans order_antisym_conv spec.cam.expansive)
qed
also have "… ≤ M⇩1"
by (rule spec.composition_principle_1[OF ‹M⇩1 ∈ spec.ap_cam_closed a⇩1› ‹M⇩1 ∈ spec.term.closed _› ‹spec.idle ≤ M⇩1›])
finally show ?thesis .
qed
theorem composition_principle:
assumes "M⇩1 ∈ spec.ap_cam_closed a⇩1"
assumes "M⇩2 ∈ spec.ap_cam_closed a⇩2"
assumes "M⇩1 ∈ spec.term.closed _"
assumes "M⇩2 ∈ spec.term.closed _"
assumes "spec.idle ≤ M⇩1"
assumes "spec.idle ≤ M⇩2"
assumes "a⇩1 ∩ a⇩2 = {}"
shows "(M⇩1 ❙⟶⇩H M⇩2) ⊓ (M⇩2 ❙⟶⇩H M⇩1) ≤ M⇩1 ⊓ M⇩2"
using assms by (metis spec.composition_principle_half inf.bounded_iff inf.commute)
text‹
An infinitary variant can be established in essentially the same way
as @{thm [source] "spec.composition_principle_1"}.
›
lemma ag_circular:
fixes Ps :: "'a ⇒ ('a, 's, 'v) spec"
assumes cam_closed: "⋀a. a ∈ as ⟹ Ps a ∈ spec.ap_cam_closed {a}"
assumes term_closed: "⋀a. a ∈ as ⟹ Ps a ∈ spec.term.closed _"
assumes idle: "⋀a. a ∈ as ⟹ spec.idle ≤ Ps a"
shows "(⨅a∈as. (⨅a'∈as-{a}. Ps a') ❙⟶⇩H Ps a) ≤ (⨅a∈as. Ps a)" (is "?lhs ≤ ?rhs")
proof(rule spec.term.closed.singleton_le_extI)
show "⦉s, xs, None⦊ ≤ ?rhs" if "⦉s, xs, None⦊ ≤ ?lhs" for s xs
using that
proof(induct xs rule: rev_induct)
case Nil from idle show ?case
by (simp add: le_INF_iff order.trans[OF spec.idle.minimal_le])
next
case (snoc x xs)
have *: "⦉s, xs, None⦊ ≤ ?rhs"
by (simp add: snoc(1) order.trans[OF spec.singleton.mono snoc(2)] trace.less_eq_same_append_conv)
have "⦉s, xs @ [x], None⦊ ≤ Ps a" if "a ∈ as" for a
proof(cases "fst x = a")
case True
with cam_closed * have "⦉s, xs @ [x], None⦊ ≤ ⨅(Ps ` (as - {a}))"
by (subst spec.cam.closed.snoc_conv[where r="⨅a'∈as-{a}. (- {a'}) × UNIV"])
(auto simp: le_INF_iff intro: subsetD[OF spec.cam.closed.antimono, rotated])
with snoc.prems(1) ‹a ∈ as› show ?thesis
by (meson heyting.mp le_INF_iff)
next
case False with cam_closed * ‹a ∈ as› show ?thesis
by (fastforce simp: spec.cam.closed.snoc_conv le_INF_iff)
qed
then show ?case by (blast intro: INFI)
qed
from term_closed show "?rhs ∈ spec.term.closed _"
by (fastforce simp: spec.term.all.monomorphic)
qed
setup ‹Sign.parent_path›
subsection‹ Interference closure\label{sec:interference_closure} ›
text‹
We add environment interference to the beginnings and ends of behaviors for two reasons:
▪ it ensures the wellformedness of parallel composition as conjunction (see \S\ref{sec:constructions-parallel_composition})
▪ it guarantees the monad laws hold (see \S\ref{sec:programs-laws})
▪ \<^const>‹spec.cam.cl› by itself is too weak to justify these
We use this closure to build the program sublattice of the \<^typ>‹('a, 's, 'v) spec› lattice (see \S\ref{sec:programs}).
Observations:
▪ if processes are made out of actions then it is not necessary to apply \<^const>‹spec.cam.cl›
›
setup ‹Sign.mandatory_path "spec"›
setup ‹Sign.mandatory_path "interference"›
definition cl :: "('a, 's) steps ⇒ ('a, 's, 'v) spec ⇒ ('a, 's, 'v) spec" where
"cl r P = spec.rel r ⤜ (λ_::unit. spec.cam.cl r P) ⤜ (λv. spec.rel r ⤜ (λ_::unit. spec.return v))"
setup ‹Sign.parent_path›
interpretation interference: closure_complete_distrib_lattice_distributive_class "spec.interference.cl r"
for r :: "('a, 's) steps"
proof
show "P ≤ spec.interference.cl r Q ⟷ spec.interference.cl r P ≤ spec.interference.cl r Q" (is "?lhs ⟷ ?rhs")
for P Q :: "('a, 's, 'v) spec"
proof(rule iffI)
assume ?lhs show ?rhs
apply (subst spec.interference.cl_def)
apply (strengthen ord_to_strengthen(1)[OF ‹?lhs›])
apply (simp add: spec.interference.cl_def spec.cam.cl.bind spec.cam.cl.return spec.cam.cl.rel
spec.bind.bind spec.bind.supL spec.bind.supR
spec.bind.returnL spec.idle_le
flip: bot_fun_def spec.bind.botR)
apply (simp add: spec.rel.wind_bind flip: spec.bind.bind)
apply (simp add: spec.bind.bind spec.bind.mono)
done
next
assume ?rhs show ?lhs
apply (strengthen ord_to_strengthen(2)[OF ‹?rhs›])
apply (simp add: spec.interference.cl_def spec.bind.bind)
apply (strengthen ord_to_strengthen(2)[OF spec.cam.expansive])
apply (strengthen ord_to_strengthen(2)[OF spec.return.rel_le])
apply (auto simp: spec.bind.return intro: spec.bind.returnL_le)
done
qed
show "spec.interference.cl r (⨆P) ≤ ⨆(spec.interference.cl r ` P) ⊔ spec.interference.cl r ⊥"
for P :: "('a, 's, 'v) spec set"
by (simp add: spec.interference.cl_def spec.cam.cl.Sup image_image
spec.bind.SupL spec.bind.supL spec.bind.SUPR
flip: bot_fun_def)
qed
setup ‹Sign.mandatory_path "term"›
setup ‹Sign.mandatory_path "none"›
setup ‹Sign.mandatory_path "interference"›
lemma cl:
shows "spec.term.none (spec.interference.cl r P) = spec.interference.cl r (spec.term.none P)"
by (simp add: spec.interference.cl_def spec.term.none.bind spec.term.none.return
spec.bind.bind spec.bind.idleR spec.bind.botR spec.term.none.cam.cl_rel_wind
flip: spec.term.none.cam.cl)
setup ‹Sign.mandatory_path "closed"›
lemma rel_le:
assumes "P ∈ spec.interference.closed r"
shows "spec.term.none (spec.rel r) ≤ P"
by (subst spec.interference.closed_conv[OF assms])
(simp add: spec.interference.cl_def spec.term.galois spec.term.all.bind spec.term.all.rel ac_simps)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "all"›
lemma cl_le:
shows "spec.interference.cl r (spec.term.all P) ≤ spec.term.all (spec.interference.cl r P)"
by (simp add: spec.interference.cl_def spec.bind.bind spec.bind.idleR spec.bind.botR
spec.term.none.bind spec.term.none.return
spec.term.none.cam.cl_rel_wind spec.term.none.cam.cl
flip: spec.term.galois)
(simp add: spec.bind.mono flip: spec.term.none.cam.cl)
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "cam.closed.interference"›
lemma cl:
shows "spec.interference.cl r P ∈ spec.cam.closed r"
by (metis spec.cam.closed_clI spec.interference.cl_def spec.interference.expansive
spec.interference.idempotent(1) spec.cam.idempotent(1))
lemma closed_subseteq:
shows "spec.interference.closed r ⊆ spec.cam.closed r"
by (metis spec.cam.closed.interference.cl spec.interference.closed_conv subsetI)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "interference"›
setup ‹Sign.mandatory_path "cl"›
lemma mono:
assumes "r ⊆ r'"
assumes "P ≤ P'"
shows "spec.interference.cl r P ≤ spec.interference.cl r' P'"
unfolding spec.interference.cl_def
apply (strengthen ord_to_strengthen(1)[OF ‹r ⊆ r'›])
apply (strengthen ord_to_strengthen(1)[OF ‹P ≤ P'›])
apply simp
done
declare spec.interference.strengthen_cl[strg del]
lemma strengthen[strg]:
assumes "st_ord F r r'"
assumes "st_ord F P P'"
shows "st_ord F (spec.interference.cl r P) (spec.interference.cl r' P')"
using assms by (cases F; simp add: spec.interference.cl.mono)
lemma bot:
shows "spec.interference.cl r ⊥ = spec.term.none (spec.rel r :: (_, _, unit) spec)"
by (simp add: spec.interference.cl_def spec.bind.bind flip: bot_fun_def spec.bind.botR)
lemmas Sup = spec.interference.cl_Sup
lemmas sup = spec.interference.cl_sup
lemma idle:
shows "spec.interference.cl r spec.idle = spec.term.none (spec.rel r :: (_, _, unit) spec)"
by (simp add: spec.interference.cl_def spec.cam.cl.idle spec.bind.bind spec.rel.wind_bind
flip: spec.term.none.bind)
lemma rel_empty:
assumes "spec.idle ≤ P"
shows "spec.interference.cl {} P = P"
by (simp add: spec.interference.cl_def spec.rel.empty spec.cam.cl.rel_empty spec.bind.return
spec.bind.returnL assms UNIV_unit)
lemma rel_reflcl:
shows "spec.interference.cl (r ∪ A × Id) P = spec.interference.cl r P"
and "spec.interference.cl (A × Id ∪ r) P = spec.interference.cl r P"
by (simp_all add: spec.interference.cl_def spec.cam.cl.rel_reflcl spec.rel.reflcl)
lemma rel_minus_Id:
shows "spec.interference.cl (r - UNIV × Id) P = spec.interference.cl r P"
by (metis Un_Diff_cancel2 spec.interference.cl.rel_reflcl(1))
lemma inf_rel:
shows "spec.interference.cl s P ⊓ spec.rel r = spec.interference.cl (r ∩ s) (spec.rel r ⊓ P)"
and "spec.rel r ⊓ spec.interference.cl s P = spec.interference.cl (r ∩ s) (spec.rel r ⊓ P)"
by (simp_all add: spec.interference.cl_def spec.bind.inf_rel spec.return.inf_rel spec.cam.cl.inf_rel
flip: spec.rel.inf)
lemma bindL:
assumes "f ∈ spec.interference.closed r"
shows "spec.interference.cl r (f ⤜ g) = f ⤜ (λv. spec.interference.cl r (g v))"
apply (subst (1 2) spec.interference.closed_conv[OF assms])
apply (simp add: spec.interference.cl_def spec.bind.bind spec.cam.cl.bind spec.cam.cl.rel
spec.cam.cl.return spec.bind.supL spec.bind.return)
apply (simp add: spec.rel.wind_bind flip: spec.bind.bind)
done
lemma bindR:
assumes "⋀v. g v ∈ spec.interference.closed r"
shows "spec.interference.cl r (f ⤜ g) = spec.interference.cl r f ⤜ g" (is "?lhs = ?rhs")
proof -
from assms have "?lhs = spec.interference.cl r (f ⤜ (λv. spec.interference.cl r (g v)))"
by (meson spec.interference.closed_conv)
also have "… = spec.interference.cl r f ⤜ (λv. spec.interference.cl r (g v))"
apply (simp add: spec.interference.cl_def spec.bind.bind spec.cam.cl.bind spec.cam.cl.rel
spec.cam.cl.return spec.bind.supL spec.bind.supR spec.bind.return
sup.absorb1 spec.bind.mono
flip: spec.bind.botR)
apply (simp add: spec.rel.wind_bind flip: spec.bind.bind)
done
also from assms have "… = ?rhs"
by (simp flip: spec.interference.closed_conv)
finally show ?thesis .
qed
lemma bind_conv:
assumes "f ∈ spec.interference.closed r"
assumes "∀x. g x ∈ spec.interference.closed r"
shows "spec.interference.cl r (f ⤜ g) = f ⤜ g"
using assms by (simp add: spec.interference.cl.bindR flip: spec.interference.closed_conv)
lemma action:
shows "spec.interference.cl r (spec.action F)
= spec.rel r ⤜ (λ_::unit. spec.action F ⤜ (λv. spec.rel r ⤜ (λ_::unit. spec.return v)))"
by (simp add: spec.interference.cl_def spec.cam.cl.action spec.bind.supL spec.bind.supR
flip: spec.bind.botR spec.bind.bind spec.rel.unwind_bind)
(simp add: spec.bind.bind sup.absorb1 spec.bind.mono)
lemma return:
shows "spec.interference.cl r (spec.return v) = spec.rel r ⤜ (λ_::unit. spec.return v)"
by (simp add: spec.return_def spec.interference.cl.action spec.bind.bind)
(simp add: spec.bind.return spec.rel.wind_bind flip: spec.return_def spec.bind.bind)
lemma bind_return:
shows "spec.interference.cl r (f ⪢ spec.return v) = spec.interference.cl r f ⪢ spec.return v"
by (simp add: spec.interference.cl_def spec.bind.bind spec.bind.return spec.cam.cl.bind_return)
lemma rel:
assumes "r ⊆ r' ∨ r' ⊆ r"
shows "spec.interference.cl r (spec.rel r') = spec.rel (r ∪ r')" (is "?lhs = ?rhs")
using assms
proof
show ?thesis if "r ⊆ r'"
apply (simp add: ‹r ⊆ r'› sup.absorb2 spec.eq_iff spec.interference.expansive)
apply (strengthen ord_to_strengthen(1)[OF ‹r ⊆ r'›])
apply (metis spec.interference.cl.bot spec.interference.idempotent(1) spec.term.all.rel
spec.term.all_none spec.term.none.interference.all.cl_le)
done
show ?thesis if "r' ⊆ r"
proof(rule antisym)
from ‹r' ⊆ r› show "?lhs ≤ ?rhs"
by (simp add: inf.absorb_iff1 spec.interference.cl.inf_rel flip: spec.rel.inf)
from ‹r' ⊆ r› show "?rhs ≤ ?lhs"
by (simp add: sup.absorb1 spec.interference.cl_def spec.cam.cl_def
spec.rel.wind_bind_trailing le_supI1 spec.bind.supR spec.bind.return
order.trans[OF _ spec.bind.mono[OF order.refl spec.bind.mono[OF spec.return.rel_le order.refl]]])
qed
qed
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "idle.interference"›
lemma cl_le[spec.idle_le]:
shows "spec.idle ≤ spec.interference.cl r P"
by (simp add: spec.interference.cl_def spec.idle_le)
lemma closed_le[spec.idle_le]:
assumes "P ∈ spec.interference.closed r"
shows "spec.idle ≤ P"
by (subst spec.interference.closed_conv[OF assms]) (simp add: spec.idle.interference.cl_le)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "map.interference"›
lemma cl_sf_id:
shows "spec.map af id vf (spec.interference.cl r P)
= spec.interference.cl (map_prod af id ` r) (spec.map af id vf P)"
apply (simp add: spec.interference.cl_def spec.map.return
spec.map.bind_inj_sf[OF inj_on_id] spec.map.cam.cl_inj_sf[OF inj_on_id])
apply (subst (1 2) spec.map.rel, force, force)
apply (simp add: spec.vmap.eq_return(2) spec.bind.bind
spec.bind.returnL spec.idle_le
flip: spec.map.cam.cl_inj_sf[where af=id and sf=id and vf=vf and P="spec.amap af P",
simplified spec.map.comp, simplified, folded id_def])
done
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "invmap.interference"›
lemma cl:
fixes as :: "'b set"
fixes af :: "'a ⇒ 'b"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
fixes r :: "('b, 't) steps"
fixes P :: "('b, 't, 'w) spec"
shows "spec.invmap af sf vf (spec.interference.cl r P)
= spec.interference.cl (map_prod af (map_prod sf sf) -` (r ∪ UNIV × Id)) (spec.invmap af sf vf P)"
apply (simp add: spec.interference.cl_def map_prod_vimage_Times spec.rel.wind_bind_trailing
spec.invmap.bind spec.invmap.cam.cl spec.invmap.rel spec.invmap.return
flip: spec.bind.bind)
apply (subst (2) spec.invmap.split_vinvmap)
apply (simp add: spec.cam.cl.bind spec.cam.cl.return spec.cam.cl.Sup spec.term.none.cam.cl_rel_wind
spec.bind.mono spec.bind.bind spec.bind.SupL spec.bind.supL
spec.bind.SUPR spec.bind.supR spec.bind.returnL spec.idle_le spec.bind.botR
image_image sup.absorb1)
done
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "interference.closed"›
lemma antimonotone:
shows "antimono spec.interference.closed"
proof(rule antimonoI)
show "spec.interference.closed r' ⊆ spec.interference.closed r" if "r ⊆ r'" for r r' :: "('a, 's) steps"
unfolding spec.interference.closed_def by (strengthen ord_to_strengthen(2)[OF ‹r ⊆ r'›]) simp
qed
lemmas strengthen[strg] = st_ord_antimono[OF spec.interference.closed.antimonotone]
lemmas antimono = antimonoD[OF spec.interference.closed.antimonotone]
lemma Sup':
assumes "X ⊆ spec.interference.closed r"
shows "⨆X ⊔ spec.term.none (spec.rel r :: (_, _, unit) spec) ∈ spec.interference.closed r"
by (metis assms spec.interference.cl.bot spec.interference.closed_Sup)
lemma Sup_not_empty:
assumes "X ⊆ spec.interference.closed r"
assumes "X ≠ {}"
shows "⨆X ∈ spec.interference.closed r"
using spec.interference.closed_Sup[OF assms(1)] assms
by (simp add: assms spec.interference.closed_Sup[OF assms(1)] less_eq_Sup spec.interference.least
subsetD sup.absorb1)
lemma rel:
assumes "r' ⊆ r"
shows "spec.rel r ∈ spec.interference.closed r'"
by (metis assms spec.eq_iff inf.absorb_iff2 spec.interference.cl.inf_rel(2) spec.interference.closed_clI)
lemma bind_relL:
fixes P :: "('a, 's, 'v) spec"
assumes "P ∈ spec.interference.closed r"
shows "spec.rel r ⤜ (λ_::unit. P) = P"
by (subst (1 2) spec.interference.closed_conv[OF assms])
(simp add: spec.interference.cl_def spec.rel.wind_bind flip: spec.bind.bind)
lemma bind_relR:
assumes "P ∈ spec.interference.closed r"
shows "P ⤜ (λv. spec.rel r ⤜ (λ_::unit. Q v)) = P ⤜ Q"
by (subst (1 2) spec.interference.closed_conv[OF assms])
(simp add: spec.interference.cl_def spec.bind.bind spec.bind.return;
simp add: spec.rel.wind_bind flip: spec.bind.bind)
lemma bind_rel_unitR:
assumes "P ∈ spec.interference.closed r"
shows "P ⪢ (spec.rel r :: (_, _, unit) spec) = P"
by (subst (1 2) spec.interference.closed_conv[OF assms])
(simp add: spec.interference.cl_def spec.bind.bind spec.rel.wind_bind)
lemma bind_rel_botR:
assumes "P ∈ spec.interference.closed r"
shows "P ⤜ (λv. spec.rel r ⤜ (λ_::unit. ⊥)) = P ⤜ ⊥"
by (subst (1 2) spec.interference.closed_conv[OF assms])
(simp add: spec.interference.cl_def spec.bind.bind spec.bind.return;
simp add: spec.rel.wind_bind flip: spec.bind.bind)
lemma bind[intro]:
fixes f :: "('a, 's, 'v) spec"
fixes g :: "'v ⇒ ('a, 's, 'w) spec"
assumes "f ∈ spec.interference.closed r"
assumes "⋀x. g x ∈ spec.interference.closed r"
shows "(f ⤜ g) ∈ spec.interference.closed r"
using assms by (simp add: spec.interference.closed_clI spec.interference.cl.bindL
flip: spec.interference.closed_conv)
lemma kleene_star:
assumes "P ∈ spec.interference.closed r"
assumes "spec.return () ≤ P"
shows "spec.kleene.star P ∈ spec.interference.closed r"
proof(rule spec.interference.closed_clI,
induct rule: spec.kleene.star.fixp_induct[where P="λR. spec.interference.cl r (R P) ≤ spec.kleene.star P ", case_names adm bot step])
case bot from ‹P ∈ spec.interference.closed r› show ?case
by (simp add: order.trans[OF _ spec.kleene.expansive_star] spec.interference.cl.bot
spec.term.none.interference.closed.rel_le)
next
case (step R) show ?case
apply (simp add: spec.interference.cl_sup spec.interference.cl.bindL[OF assms(1)])
apply (strengthen ord_to_strengthen(1)[OF step])
apply (strengthen ord_to_strengthen(1)[OF ‹spec.return () ≤ P›])
apply (simp add: spec.kleene.fold_starL spec.kleene.expansive_star
flip: spec.interference.closed_conv[OF assms(1)])
done
qed simp_all
lemma map_sf_id:
fixes af :: "'a ⇒ 'b"
fixes vf :: "'v ⇒ 'w"
assumes "P ∈ spec.interference.closed r"
shows "spec.map af id vf P ∈ spec.interference.closed (map_prod af id ` r)"
by (rule spec.interference.closed_clI)
(subst (2) spec.interference.closed_conv[OF assms];
simp add: spec.map.interference.cl_sf_id map_prod_image_Times)
lemma invmap:
fixes af :: "'a ⇒ 'b"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
assumes "P ∈ spec.interference.closed r"
shows "spec.invmap af sf vf P ∈ spec.interference.closed (map_prod af (map_prod sf sf) -` r)"
by (rule spec.interference.closed_clI)
(subst (2) spec.interference.closed_conv[OF assms];
fastforce simp: spec.invmap.interference.cl intro: spec.interference.cl.mono)
setup ‹Sign.mandatory_path "term"›
lemma none:
assumes "P ∈ spec.interference.closed r"
shows "spec.term.none P ∈ spec.interference.closed r"
by (rule spec.interference.closed_clI)
(subst (2) spec.interference.closed_conv[OF assms];
simp add: spec.term.none.interference.cl)
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
subsection‹ The ∗‹'a agent› datatype ›
text‹
For compositionality we often wish to designate a specific agent as the environment.
›