Theory Local_State
theory Local_State
imports
Programs
begin
lemmas trace_steps'_map =
trace.steps'.map(1)[where af=id and sf="Pair (fst (trace.final' (ls, s) xs))" and s="snd (trace.final' (ls, s) xs)", simplified]
trace.steps'.map(1)[where af=id and sf="Pair x"]
for ls s xs x
lemma trace_steps'_snd_le_const:
assumes "trace.steps' (ls, s) xs ⊆ {(a, (ls', s'), (ls'', s'))}"
shows "(λx. snd (snd x)) ` set xs ⊆ {s}"
using subset_singletonD[OF assms] by (force simp: trace.steps'.step_conv image_subset_iff)
lemma trace_natural'_took_step_shared_changes:
assumes "trace.steps' (ls, s) xs ⊆ {(a, (ls'', s''), (ls''', s'''))}"
assumes "trace.final' (ls, s) xs = (ls', s')"
assumes "s ≠ s'"
shows "trace.natural' s (map (map_prod id snd) xs) = [(a, s')]"
using subset_singletonD[OF assms(1)] assms(2-)
by (auto simp: trace.steps'.step_conv trace.natural'.append trace.natural'.eq_Nil_conv
image_subset_iff append_eq_Cons_conv)
lemma trace_natural'_took_step_shared_same:
assumes "trace.steps' (ls, s) xs ⊆ {(a, (ls'', s'), (ls''', s'))}"
assumes "alss ∈ set xs"
shows "snd (snd alss) = s"
using subset_singletonD[OF assms(1)] assms(2)
by (fastforce simp: trace.steps'.step_conv image_subset_iff)
section‹ Structural local state\label{sec:local_state} ›
subsection‹ ∗‹spec.local›\label{sec:local_state-spec_local} ›
text‹
We develop a few combinators for structural local state. The goal is to encapsulate a local state
of type \<^typ>‹'ls› in a process \<^typ>‹('a agent, 'ls × 's, 'v) spec›. Applying \<^term>‹spec.smap snd›
yields a process of type \<^typ>‹('a agent, 's, 'v) spec›. We also constrain environment steps
to not affect \<^typ>‹'ls›, yielding a plausible data refinement rule
(see \S\ref{sec:local_state-data_refinement}).
›
abbreviation (input) localize1 :: "('b ⇒ 's ⇒ 'a) ⇒ 'b ⇒ 'ls × 's ⇒ 'a" where
"localize1 f b s ≡ f b (snd s)"
setup ‹Sign.mandatory_path "spec"›
setup ‹Sign.mandatory_path "local"›
definition qrm :: "('a agent, 'ls × 's) steps" where
"qrm = range proc × UNIV ∪ {env} × (Id ×⇩R UNIV)"
abbreviation (input) "interference ≡ spec.rel spec.local.qrm"
setup ‹Sign.parent_path›
definition local :: "('a agent, 'ls × 's, 'v) spec ⇒ ('a agent, 's, 'v) spec" where
"local P = spec.smap snd (spec.local.interference ⊓ P)"
setup ‹Sign.mandatory_path "singleton"›
lemma local_le_conv:
shows "⦉σ⦊ ≤ spec.local P
⟷ (∃σ'. ⦉σ'⦊ ≤ P
∧ trace.steps σ' ⊆ spec.local.qrm
∧ ⦉σ⦊ ≤ ⦉trace.map id snd id σ'⦊)"
by (simp add: spec.local_def spec.singleton.le_conv ac_simps)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "idle"›
lemma local_le[spec.idle_le]:
assumes "spec.idle ≤ P"
shows "spec.idle ≤ spec.local P"
by (simp add: spec.local_def assms spec.idle_le)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "local"›
setup ‹Sign.mandatory_path "qrm"›
lemma refl:
shows "refl (spec.local.qrm `` {a})"
by (simp add: spec.local.qrm_def refl_onI)
lemma member:
shows "(proc a, s, s') ∈ spec.local.qrm"
and "(env, s, s') ∈ spec.local.qrm ⟷ fst s = fst s'"
by (auto simp: spec.local.qrm_def)
lemma inter:
shows "UNIV × Id ∩ spec.local.qrm = UNIV × Id"
and "spec.local.qrm ∩ UNIV × Id = UNIV × Id"
and "spec.local.qrm ∩ {self} × Id = {self} × Id"
and "spec.local.qrm ∩ {env} × UNIV = {env} × (Id ×⇩R UNIV)"
and "spec.local.qrm ∩ {env} × (UNIV ×⇩R Id) = {env} × Id"
and "spec.local.qrm ∩ A × (Id ×⇩R r) = A × (Id ×⇩R r)"
by (auto simp: spec.local.qrm_def)
lemmas simps[simp] =
spec.local.qrm.refl
spec.local.qrm.member
spec.local.qrm.inter
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "interference"›
lemma smap_snd:
shows "spec.smap snd spec.local.interference = ⊤"
by (subst spec.map.rel)
(auto simp: spec.local.qrm_def spec.rel.UNIV
image_Un map_prod_image_Times map_prod_image_relprod map_prod_surj
simp flip: Sigma_Un_distrib1)
setup ‹Sign.parent_path›
lemma inf_interference:
shows "spec.local P = spec.local (P ⊓ spec.local.interference)"
by (simp add: spec.local_def ac_simps)
lemma bot:
shows "spec.local ⊥ = ⊥"
by (simp add: spec.local_def spec.map.bot)
lemma top:
shows "spec.local ⊤ = ⊤"
by (simp add: spec.local_def spec.local.interference.smap_snd)
lemma monotone:
shows "mono spec.local"
proof(rule monotoneI)
show "spec.local P ≤ spec.local P'" if "P ≤ P'" for P P' :: "('a agent, 's × 'ls, 'v) spec"
unfolding spec.local_def by (strengthen ord_to_strengthen(1)[OF ‹P ≤ P'›]) simp
qed
lemmas strengthen[strg] = st_monotone[OF spec.local.monotone]
lemmas mono = monotoneD[OF spec.local.monotone]
lemmas mono2mono[cont_intro, partial_function_mono]
= monotone2monotone[OF spec.local.monotone, simplified, of orda P for orda P]
lemma Sup:
shows "spec.local (⨆X) = (⨆x∈X. spec.local x)"
by (simp add: spec.local_def inf_Sup spec.map.Sup image_image)
lemmas sup = spec.local.Sup[where X="{X, Y}" for X Y, simplified]
lemma mcont2mcont[cont_intro]:
assumes "mcont luba orda Sup (≤) P"
shows "mcont luba orda Sup (≤) (λx. spec.local (P x))"
by (simp add: spec.local_def assms)
lemma idle:
shows "spec.local spec.idle = spec.idle"
by (simp add: spec.local_def inf.absorb2[OF spec.idle.rel_le] spec.map.idle)
lemma action:
fixes F :: "('v × 'a agent × ('ls × 's) × ('ls × 's)) set"
shows "spec.local (spec.action F)
= spec.action (map_prod id (map_prod id (map_prod snd snd)) `
(F ∩ UNIV × spec.local.qrm))"
by (simp add: spec.local_def spec.action.inf_rel spec.map.surj_sf_action)
lemma return:
shows "spec.local (spec.return v) = spec.return v"
by (simp add: spec.return_def spec.local.action
Times_Int_Times map_prod_image_Times map_prod_snd_snd_image_Id)
lemma bind_le:
shows "spec.local (f ⤜ g) ≤ spec.local f ⤜ (λv. spec.local (g v))"
by (simp add: spec.local_def spec.bind.inf_rel spec.map.bind_le)
lemma interference:
shows "spec.local (spec.rel ({env} × UNIV)) = spec.rel ({env} × UNIV)"
by (simp add: spec.local_def spec.map.rel map_prod_image_Times map_prod_image_relprod
flip: spec.rel.inf)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "map"›
lemma local_le:
shows "spec.map id sf vf (spec.local P) ≤ spec.local (spec.map id (map_prod id sf) vf P)"
by (fastforce intro: spec.map.mono inf.mono spec.rel.mono
simp: spec.local_def spec.map.comp spec.map.inf_rel spec.local.qrm_def)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "vmap"›
lemma local:
shows "spec.vmap vf (spec.local P) = spec.local (spec.vmap vf P)"
by (simp add: spec.local_def spec.map.comp spec.map.inf_rel spec.rel.reflcl(1)[where A=UNIV])
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "invmap"›
lemma smap_snd:
fixes P :: "('a, 'ls × 't, 'w) spec"
fixes sf :: "'s ⇒ 't"
fixes vf :: "'v ⇒ 'w"
shows "spec.invmap id sf vf (spec.smap snd P)
= spec.smap snd (spec.invmap id (map_prod id sf) vf P)" (is "?lhs = ?rhs")
proof(rule spec.singleton.antisym)
have smap_snd_aux:
"∃zs. trace.natural' (ls, sf s) xs = trace.natural' (ls, sf s) (map (map_prod id (map_prod id sf)) zs)
∧ trace.natural' s (map (map_prod id snd) zs) = trace.natural' s ys" (is "∃zs. ?P ls s ys zs")
if "trace.natural' (sf s) (map (map_prod id sf) ys) = trace.natural' (sf s) (map (map_prod id snd) xs)"
for ls and s :: "'s" and sf :: "'s ⇒ 't" and xs :: "('a × 'ls × 't) list" and ys :: "('a × 's) list"
using that
proof(induct xs arbitrary: ls s ys)
case (Nil ls s ys) then show ?case
by (fastforce intro: exI[where x="map (map_prod id (Pair ls)) ys"]
simp: comp_def trace.natural'.eq_Nil_conv)
next
case (Cons x xs ls s ys) show ?case
proof(cases "snd (snd x) = sf s")
case True with Cons.prems show ?thesis
by (cases x) (fastforce dest: Cons.hyps[where ls="fst (snd x)"]
intro: exI[where x="(fst x, fst (snd x), s) # zs" for zs]
simp flip: id_def)
next
case False
with Cons.prems obtain a s⇩x us s' zs
where "x = (a, s⇩x, sf s')"
and "sf s' ≠ sf s"
and "snd ` map_prod id sf ` set us ⊆ {sf s}"
and "ys = us @ (a, s') # zs"
and "trace.natural' (sf s') (map (map_prod id sf) zs) = trace.natural' (sf s') (map (map_prod id snd) xs)"
by (cases x) (clarsimp simp: trace.natural'.eq_Cons_conv map_eq_append_conv simp flip: id_def)
with False show ?thesis
by (fastforce simp: comp_def trace.natural'.append image_subset_iff trace.natural'.eq_Nil_conv
intro: exI[where x="map (map_prod id (Pair ls)) us @ (a, (s⇩x, s')) # zs" for zs]
dest: Cons.hyps[where ls="fst (snd x)"])
qed
qed
fix σ
assume "⦉σ⦊ ≤ ?lhs"
then obtain ls xs v i
where *: "⦉(ls, sf (trace.init σ)), xs, v⦊ ≤ P"
and **: "trace.natural' (sf (trace.init σ)) (map (map_prod id sf) (trace.rest σ))
= trace.natural' (sf (trace.init σ)) (map (map_prod id snd) (take i xs))"
and ***: "if i ≤ length xs then trace.term σ = None else map_option vf (trace.term σ) = v"
apply (clarsimp simp: spec.singleton.le_conv spec.singleton_le_conv)
apply (erule trace.less_eq_takeE)
apply (erule trace.take.naturalE)
apply (clarsimp simp: trace.take.map trace.natural_def trace.split_all not_le
split: if_split_asm)
apply (metis order.strict_iff_not take_all)
done
from smap_snd_aux[OF **] obtain zs
where "trace.natural' (ls, sf (trace.init σ)) (take i xs)
= trace.natural' (ls, sf (trace.init σ)) (map (map_prod id (map_prod id sf)) zs)"
and "trace.natural' (trace.init σ) (map (map_prod id snd) zs)
= trace.natural' (trace.init σ) (trace.rest σ)"
by blast
with * *** show "⦉σ⦊ ≤ ?rhs"
apply -
unfolding spec.singleton.le_conv
apply (rule exI[where x="trace.T (ls, trace.init σ) zs (if i ≤ length xs then None else trace.term σ)"])
apply (clarsimp simp: spec.singleton_le_conv trace.natural_def trace.less_eq_None
split: if_splits
elim!: order.trans[rotated])
apply (metis append_take_drop_id prefixI trace.natural'.append)
done
next
show "⦉σ⦊ ≤ ?lhs" if "⦉σ⦊ ≤ ?rhs" for σ
using that
by (fastforce dest: spec.singleton.map_le[where af=id and sf=sf and vf=vf]
simp: spec.singleton.le_conv)
qed
lemma local:
fixes P :: "('a agent, 'ls × 't, 'v) spec"
fixes sf :: "'s ⇒ 't"
shows "spec.invmap id sf vf (spec.local P) = spec.local (spec.invmap id (map_prod id sf) vf P)"
by (auto simp: spec.local_def spec.local.qrm_def ac_simps
spec.invmap.smap_snd spec.invmap.inf spec.invmap.rel
intro!: arg_cong[where f="λr. spec.smap snd (spec.invmap id (map_prod id sf) vf P ⊓ spec.rel r)"])
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "term"›
setup ‹Sign.mandatory_path "none"›
lemma local:
shows "spec.term.none (spec.local P) = spec.local (spec.term.none P)"
by (simp add: spec.local_def spec.term.none.inf spec.term.none.inf_none_rel spec.term.none.map)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "all"›
lemma local:
shows "spec.term.all (spec.local P) = spec.local (spec.term.all P)"
by (simp add: spec.local_def spec.term.all.map spec.term.all.rel spec.term.all.inf)
setup ‹Sign.parent_path›
setup ‹Sign.mandatory_path "closed"›
lemma local:
assumes "P ∈ spec.term.closed _"
shows "spec.local P ∈ spec.term.closed _"
by (rule spec.term.closed_clI)
(simp add: spec.term.all.local spec.term.all.monomorphic
flip: spec.term.closed_conv[OF assms, simplified])
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›
subsection‹ Local state transformations\label{sec:local_state-transformations} ›
text‹
We want to reorder, introduce and eliminate actions that affect local state while preserving
observable behaviour under \<^const>‹spec.local›.
The closure that arises from \<^const>‹spec.local›, i.e.:
›
lemma
defines "cl ≡ spec.map_invmap.cl _ _ _ id snd id"
assumes "spec.local.interference ⊓ P
≤ cl (spec.local.interference ⊓ Q)"
shows "spec.local P ≤ spec.local Q"
unfolding spec.local_def
by (strengthen ord_to_strengthen(1)[OF assms(2)])
(simp add: spec.map_invmap.galois cl_def spec.map_invmap.cl_def)
text‹
expresses all transformations, but does not decompose over \<^const>‹spec.bind›; in other
words we do not have ‹cl f ⤜ (λv. cl (g v)) ≤ cl (f ⤜ g)› as the
local states that ‹cl f› terminates with may not satisfy ‹g›. (Observe that we do not expect the
converse to hold as then all local states would need to be preserved.)
We therefore define a closure that preserves the observable state and
the initial and optionally final (if terminating) local states via a projection:
›
setup ‹Sign.mandatory_path "seq_ctxt"›
definition prj :: "bool ⇒ ('a, 'ls × 's, 'v) trace.t ⇒ ('a, 's, 'v) trace.t × 'ls × 'ls option" where
"prj T σ = (♮(trace.map id snd id σ),
fst (trace.init σ),
if T then map_option ⟨fst (trace.final σ)⟩ (trace.term σ) else None)"
setup ‹Sign.mandatory_path "prj"›
lemma natural:
shows "seq_ctxt.prj T (♮σ) = seq_ctxt.prj T σ"
by (simp add: seq_ctxt.prj_def trace.natural.map_natural)
lemma idle:
shows "seq_ctxt.prj T (trace.T s [] None) = (trace.T (snd s) [] None, fst s, None)"
by (simp add: seq_ctxt.prj_def trace.natural.simps)
lemmas simps[simp] =
seq_ctxt.prj.natural
setup ‹Sign.parent_path›
setup ‹Sign.parent_path›