(*>*) section‹ A programming language\label{sec:programs} ›
text‹
🍋‹('a, 's, 'v) spec› lattice of
S\ref{sec:safety_logic-logic} is adequate for logic but is deficient
a programming language. In particular we wish to interpret the
composition as intersection \S\ref{sec:constructions-parallel_composition}) which requires
to contain enough interference opportunities. Similarly we
the customary ``laws of programming'' 🍋‹"HoareEtAl:1987"› to hold without side
.
points are discussed at some length by 🍋‹‹\S3.2› in "Zwiers:1989"› and also 🍋‹‹Lemma~6.7› in "Foster:2020"›.
‹('v, 's) prog› lattice (\S\ref{sec:programs-prog})
handles the common case of the familiar constructs for
programming, and we lean on our 🍋‹('a, 's, 'v) › lattice for other constructions such as interleaving
composition (\S\ref{sec:constructions-parallel_composition})
local state (\S\ref{sec:local_state}). It allows arbitrary
by the environment before and after every program action.
›
subsection‹ The 🪙‹('s, 'v) prog› lattice \label{sec:programs-prog} ›
text‹
to 🍋‹‹\S2.1› in "MuellerOlm:1997"›, ‹('s, 'v) prog› is 🪙‹sub-lattice› of 🍋‹('a, 's, 'v) spec› as the corresponding const‹inf› and const‹sup›
coincide. However it is not a 🪙‹complete› sub-lattice as const‹Sup› in ‹('s, 'v) prog›
to account for the higher bottom of that lattice.
instance by standard (transfer; auto simp: Inf_lower InfI SupI le_supI1 spec.interference.least)+
end
subsection‹ Morphisms to and from the 🪙‹(sequential, 's, 'v) spec› lattice\label{sec:programs-morphisms} ›
text‹
can readily convert a 🍋‹('s, 'v) prog› into a 🍋‹('a agent, 's, 'v) spec›. More interestingly, on 🍋‹('s, 'v) prog› we have a Galois connection that
specifications into programs. (This connection is termed a 🪙‹Galois insertion› by 🍋‹"MeltonSchmidtStrecker:1985"› as we also have ‹prog.s2p.p2s›; Cousot says ``Galois retraction''.)
also \S\ref{sec:programs-refinement-galois} and
S\ref{sec:programs-ag-galois}.
subsection‹ Programming language constructs\label{sec:programs-language} ›
text‹
lift the combinators directly from the 🍋‹('a,
s ,'v) spec› lattice (\S\ref{sec:safety_logic}), but need to
-close primitive actions. Control flow is expressed via
's ‹if-then-else› construct and other case combinators
the scrutinee is a pure value. This means that the atomicity of a process is completely
by occurrences of ‹prog.action›.
lemma inf_le: shows"prog.action (F ⊓ G) ≤ prog.action F ⊓ prog.action G" using prog.action.Inf_le[where Fs="{F, G}"] by simp
lemma sinvmap_le: ―‹ a strict refinement › shows"prog.p2s (prog.action (map_prod id (map_prod sf sf) -` F)) ≤ spec.sinvmap sf (prog.p2s (prog.action F))" by (force intro: order.trans[OF _ spec.interference.cl.mono[OF order.refl spec.action.invmap_le]]
spec.interference.cl.mono spec.action.mono
simp: prog.p2s.action spec.invmap.interference.cl)
lemma return_const: fixes F :: "'s rel" fixes V :: "'v set" fixes W :: "'w set" assumes"V ≠ {}" assumes"W ≠ {}" shows"prog.action (V × F) = prog.action (W × F) 🍋 (⊔v∈V. prog.return v)" using assms(1) by (simp add: prog.p2s.simps prog.p2s.action prog.p2s.return image_image
map_prod_image_Times spec.action.return_const[OF assms]
spec.bind.SUPR_not_empty spec.interference.cl.bind_return
spec.interference.cl.return spec.interference.cl_Sup_not_empty
spec.interference.closed.bind_relR
flip: prog.p2s_inject)
lemma rel_le: assumes"∧v s s'. (v, s, s') ∈ F ==> (s, s') ∈ r ∨ s = s'" shows"prog.action F ≤ prog.rel r" by (auto intro: order.trans[OF spec.interference.cl.mono[OF order.refl
spec.action.rel_le[where r="{self} × r ∪ {env} × UNIV"]]]
dest: assms
simp: less_eq_prog.rep_eq prog.p2s.simps prog.p2s.action spec.interference.cl.rel ac_simps)
lemma invmap_le: shows"prog.action (map_prod vf (map_prod sf sf) -` F) ≤ prog.invmap sf vf (prog.action F)" by transfer
(force simp: spec.invmap.interference.cl
intro: spec.interference.cl.mono
spec.action.mono order.trans[OF _ spec.interference.cl.mono[OF order.refl spec.action.invmap_le]])
lemma action_le: shows"spec.action (map_prod id (Pair self) ` F) ≤ prog.p2s (prog.action F)" by (simp add: prog.p2s.action spec.interference.expansive)
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "bind"›
lemmas if_distrL = if_distrib[where f="λx. x 🍋 g"for g :: "_ ==> (_, _) prog"]
lemma mono: assumes"f ≤ f'" assumes"∧x. g x ≤ g' x" shows"prog.bind f g ≤ prog.bind f' g'" using assms by transfer (simp add: spec.bind.mono)
lemma strengthen[strg]: assumes"st_ord F f f'" assumes"∧x. st_ord F (g x) (g' x)" shows"st_ord F (prog.bind f g) (prog.bind f' g')" using assms by (cases F; clarsimp intro!: prog.bind.mono)
lemma mono2mono[cont_intro, partial_function_mono]: assumes"monotone orda (≤) f" assumes"∧x. monotone orda (≤) (λy. g y x)" shows"monotone orda (≤) (λx. prog.bind (f x) (g x))" using assms by transfer simp
text‹ The monad laws hold unconditionally in the 🍋‹('s, 'v) prog› lattice. ›
lemma bind: shows"f 🍋 g 🍋 h = prog.bind f (λx. g x 🍋 h)" by transfer (simp add: spec.bind.bind)
lemma return: shows returnL: "(🍋) (prog.return v) = (λg :: 'v ==> ('s, 'w) prog. g v)" (is ?thesis1) and returnR: "f 🍋 prog.return = f" (is ?thesis2) proof - have"prog.return v 🍋 g = g v"for g :: "'v ==> ('s, 'w) prog" by transfer
(simp add: map_prod_image_Times Pair_image spec.action.read_agents
spec.interference.cl.return spec.bind.bind
spec.bind.returnL spec.idle_le prog.p2s_induct spec.interference.closed.bind_relL
flip: spec.return_def) thenshow ?thesis1 by (simp add: fun_eq_iff) show ?thesis2 by transfer
(simp add: map_prod_image_Times Pair_image spec.action.read_agents
flip: spec.interference.cl.bindL spec.return_def spec.interference.closed_conv) qed
lemma botR_le: shows"prog.bind f ⟨⊥⟩≤ f" (is ?thesis1) and"prog.bind f ⊥≤ f" (is ?thesis2) proof - show ?thesis1 by (metis bot.extremum dual_order.refl prog.bind.mono prog.bind.returnR) thenshow ?thesis2 by (simp add: bot_fun_def) qed
lemma fixes f :: "(_, _) prog" fixes f1 :: "(_, _) prog" shows supL: "(f1⊔ f2) 🍋 g = (f1🍋 g) ⊔ (f2🍋 g)" and supR: "f 🍋 (λx. g1 x ⊔ g2 x) = (f 🍋 g1) ⊔ (f 🍋 g2)" by (transfer; blast intro: spec.bind.supL spec.bind.supR)+
lemma SUPL: fixes X :: "_ set" fixes f :: "_ ==> (_, _) prog" shows"(⊔x∈X. f x) 🍋 g = (⊔x∈X. f x 🍋 g)" by transfer
(simp add: spec.interference.cl.bot spec.bind.supL spec.bind.bind spec.bind.SUPL
flip: spec.bind.botR bot_fun_def)
lemma SUPR: fixes X :: "_ set" fixes f :: "(_, _) prog" shows"f 🍋 (λv. ⊔x∈X. g x v) = (⊔x∈X. f 🍋 g x) ⊔ (f 🍋⊥)" unfolding bot_fun_def by transfer
(simp add: spec.bind.supL spec.bind.supR spec.bind.bind spec.bind.SUPR ac_simps le_supI2
spec.interference.closed.bind_rel_botR
sup.absorb2 spec.interference.closed.bind spec.interference.least spec.bind.mono
flip: spec.bind.botR)
lemma SupR: fixes X :: "_ set" fixes f :: "(_, _) prog" shows"f 🍋 (⊔X) = (⊔x∈X. f 🍋 x) ⊔ (f 🍋⊥)" by (simp add: prog.bind.SUPR[where g="λx v. x", simplified])
lemma SUPR_not_empty: fixes f :: "(_, _) prog" assumes"X ≠ {}" shows"f 🍋 (λv. ⊔x∈X. g x v) = (⊔x∈X. f 🍋 g x)" using iffD2[OF ex_in_conv assms] by (subst trans[OF prog.bind.SUPR sup.absorb1]; force intro: SUPI prog.bind.mono)
lemma mcont2mcont[cont_intro]: assumes"mcont luba orda Sup (≤) f" assumes"∧v. mcont luba orda Sup (≤) (λx. g x v)" shows"mcont luba orda Sup (≤) (λx. prog.bind (f x) (g x))" proof(rule ccpo.mcont2mcont'[OF complete_lattice_ccpo _ _ assms(1)]) show"mcont Sup (≤) Sup (≤) (λf. prog.bind f (g x))"for x by (intro mcontI contI monotoneI) (simp_all add: prog.bind.mono flip: prog.bind.SUPL) show"mcont luba orda Sup (≤) (λx. prog.bind f (g x))"for f by (intro mcontI monotoneI contI)
(simp_all add: mcont_monoD[OF assms(2)] prog.bind.mono
flip: prog.bind.SUPR_not_empty contD[OF mcont_cont[OF assms(2)]]) qed
lemma inf_rel: shows"prog.rel r ⊓ (f 🍋 g) = prog.rel r ⊓ f 🍋 (λx. prog.rel r ⊓ g x)" and"(f 🍋 g) ⊓ prog.rel r = prog.rel r ⊓ f 🍋 (λx. prog.rel r ⊓ g x)" by (transfer; simp add: spec.bind.inf_rel)+
lemma less: ―‹ Non-triviality › assumes"g < g'" shows"prog.guard g < prog.guard g'" proof(rule le_neq_trans) show"prog.guard g ≤ prog.guard g'" by (strengthen ord_to_strengthen(1)[OF order_less_imp_le[OF assms]]) simp from assms obtain s where"g' s""¬g s"by (metis leD predicate1I) from‹¬g s›have"¬(•trace.T s [] (Some ())•)≤ prog.p2s (prog.guard g)" by (fastforce simp: trace.split_all prog.p2s.guard spec.guard_def spec.interference.cl.action
spec.singleton.le_conv spec.singleton.action_le_conv trace.steps'.step_conv
elim: spec.singleton.bind_le) moreover from‹g' s›have"(•trace.T s [] (Some ())•)≤ prog.p2s (prog.guard g')" by (force simp: prog.p2s.guard prog.p2s.action spec.guard_def
intro: order.trans[OF _ spec.interference.expansive] spec.action.stutterI) ultimatelyshow"prog.guard g ≠ prog.guard g'"by metis qed
lemma"if": shows"(if b then t else e) = (prog.guard ⟨b⟩🍋 t) ⊔ (prog.guard ⟨¬b⟩🍋 e)" by (auto simp: prog.guard.bot prog.guard.top prog.bind.returnL prog.bind.botL)
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "Parallel"›
lemma bot: assumes"∧a. a ∈ bs ==> Ps a = ⊥" assumes"as ∩ bs ≠ {}" shows"prog.Parallel as Ps = prog.Parallel (as - bs) Ps 🍋⊥" by (auto simp: assms(1)
prog.p2s.simps spec.interference.cl.bot
spec.interference.closed.bind_rel_unitR spec.interference.closed.Parallel
spec.term.none.Parallel_some_agents[OF _ assms(2), where Ps'="⟨spec.rel ({env} × UNIV)⟩"]
spec.Parallel.discard_interference[where as=as and bs="as ∩ bs"]
simp del: Int_iff
simp flip: prog.p2s_inject spec.bind.botR spec.bind.bind
intro: arg_cong[OF spec.Parallel.cong])
lemma mono: assumes"∧a. a ∈ as ==> Ps a ≤ Ps' a" shows"prog.Parallel as Ps ≤ prog.Parallel as Ps'" using assms by transfer (blast intro: spec.Parallel.mono)
lemma strengthen_Parallel[strg]: assumes"∧a. a ∈ as ==> st_ord F (Ps a) (Ps' a)" shows"st_ord F (prog.Parallel as Ps) (prog.Parallel as Ps')" using assms by (cases F) (auto simp: prog.Parallel.mono)
lemma mono2mono[cont_intro, partial_function_mono]: assumes"∧a. a ∈ as ==> monotone orda (≤) (F a)" shows"monotone orda (≤) (λf. prog.Parallel as (λa. F a f))" using assms by transfer (simp add: spec.Parallel.mono2mono)
lemma cong: assumes"as = as'" assumes"∧a. a ∈ as' ==> Ps a = Ps' a" shows"prog.Parallel as Ps = prog.Parallel as' Ps'" using assms by transfer (rule spec.Parallel.cong; simp)
lemma no_agents: shows"prog.Parallel {} Ps = prog.return ()" by transfer
(simp add: spec.Parallel.no_agents spec.interference.cl.return map_prod_image_Times Pair_image
spec.action.read_agents)
lemma singleton_agents: shows"prog.Parallel {a} Ps = Ps a" by transfer (rule spec.Parallel.singleton_agents)
lemma rename_UNIV: assumes"inj_on f as" shows"prog.Parallel as Ps = prog.Parallel UNIV (λb. if b ∈ f ` as then Ps (inv_into as f b) else prog.return ())" by (simp add: prog.p2s.simps if_distrib prog.p2s.return spec.interference.cl.return
spec.Parallel.rename_UNIV[OF assms]
flip: prog.p2s_inject
cong: spec.Parallel.cong if_cong)
lemmasrename = spec.Parallel.rename[transferred]
lemma return: assumes"∧a. a ∈ bs ==> Ps a = prog.return ()" shows"prog.Parallel as Ps = prog.Parallel (as - bs) Ps" by (subst (12) prog.Parallel.rename_UNIV[where f=id, simplified])
(auto intro: arg_cong[where f="prog.Parallel UNIV"]
simp: assms fun_eq_iff f_inv_into_f[where f=id, simplified])
lemma unwind: assumes a: "f 🍋 g ≤ Ps a" ―‹ The selected process starts with action ‹f›› assumes"a ∈ as" shows"f 🍋 (λv. prog.Parallel as (Ps(a:=g v))) ≤ prog.Parallel as Ps" using assms by transfer (simp add: spec.Parallel.unwind spec.interference.closed.bind_relL)
lemma strengthen[strg]: assumes"st_ord F P P'" assumes"st_ord F Q Q'" shows"st_ord F (prog.parallel P Q) (prog.parallel P' Q')" using assms by (cases F; simp add: prog.parallel.mono)
lemma bot: shows botL: "prog.parallel ⊥ P = P 🍋⊥" (is ?thesis1) and botR: "prog.parallel P ⊥ = P 🍋⊥" (is ?thesis2) proof - show ?thesis1 by (simp add: prog.parallel_alt_def prog.Parallel.bot[where bs="{True}", simplified]
prog.Parallel.singleton_agents
cong: prog.Parallel.cong) thenshow ?thesis2 by (simp add: prog.parallel.commute) qed
lemma return: shows returnL: "prog.return () ∥ P = P" (is ?thesis1) and returnR: "P ∥ prog.return () = P" (is ?thesis2) proof - show ?thesis1 by (simp add: prog.parallel_alt_def prog.Parallel.return[where bs="{True}", simplified]
prog.Parallel.singleton_agents) thenshow ?thesis2 by (simp add: prog.parallel.commute) qed
lemma Sup_not_empty: fixes X :: "(_, unit) prog set" assumes"X ≠ {}" shows SupL_not_empty: "⊔X ∥ Q = (⊔P∈X. P ∥ Q)" (is"?thesis1 Q") and SupR_not_empty: "P ∥⊔X = (⊔Q∈X. P ∥ Q)" (is ?thesis2) proof - from assms show"?thesis1 Q"for Q by (simp add: prog.p2s.parallel prog.p2s.Sup_not_empty[OF assms] image_image
spec.parallel.Sup prog.p2s.SUP_not_empty
flip: prog.p2s_inject) thenshow ?thesis2 by (simp add: prog.parallel.commute) qed
lemma sup: fixes P :: "(_, unit) prog" shows supL: "P ⊔ Q ∥ R = (P ∥ R) ⊔ (Q ∥ R)" and supR: "P ∥ Q ⊔ R = (P ∥ Q) ⊔ (P ∥ R)" using prog.parallel.SupL_not_empty[where X="{P, Q}"] prog.parallel.SupR_not_empty[where X="{Q, R}"] by simp_all
lemma mcont2mcont[cont_intro]: assumes"mcont luba orda Sup (≤) P" assumes"mcont luba orda Sup (≤) Q" shows"mcont luba orda Sup (≤) (λx. prog.parallel (P x) (Q x))" proof(rule ccpo.mcont2mcont'[OF complete_lattice_ccpo _ _ assms(1)]) show"mcont Sup (≤) Sup (≤) (λy. prog.parallel y (Q x))"for x by (intro mcontI contI monotoneI) (simp_all add: prog.parallel.mono prog.parallel.SupL_not_empty) show"mcont luba orda Sup (≤) (λx. prog.parallel y (Q x))"for y by (simp add: mcontI monotoneI contI mcont_monoD[OF assms(2)]
spec.parallel.mono mcont_contD[OF assms(2)] prog.parallel.SupR_not_empty image_image) qed
lemma unwindL: fixes f :: "('s, 'v) prog" assumes a: "f 🍋 g ≤ P" ―‹ The selected process starts with action ‹f›› shows"f 🍋 (λv. g v ∥ Q) ≤ P ∥ Q" unfolding prog.parallel_alt_def by (strengthen ord_to_strengthen[OF prog.Parallel.unwind[where a=True]])
(auto simp: prog.Parallel.mono prog.bind.mono intro: assms)
lemma unwindR: fixes f :: "('s, 'v) prog" assumes a: "f 🍋 g ≤ Q" ―‹ The selected process starts with action ‹f›› shows"f 🍋 (λv. P ∥ g v) ≤ P ∥ Q" by (subst (12) prog.parallel.commute) (rule prog.parallel.unwindL[OF assms])
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "bind"›
lemma parallel_le: fixes P :: "(_, _) prog" shows"P 🍋 Q ≤ P ∥ Q" by (strengthen ord_to_strengthen[OF prog.parallel.unwindL[where g=prog.return, simplified prog.bind.returnR, OF order.refl]])
(simp add: prog.parallel.return)
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "invmap"›
lemma bot: shows"prog.invmap sf vf ⊥ = (prog.rel (map_prod sf sf -` Id) :: (_, unit) prog) 🍋⊥" by (auto simp: prog.p2s.simps spec.interference.cl.bot spec.rel.wind_bind_trailing
spec.invmap.bind spec.invmap.rel spec.invmap.bot
simp flip: prog.p2s_inject spec.bind.botR spec.bind.bind bot_fun_def
intro: arg_cong[where f="λr. spec.rel r 🍋⊥"])
lemma id: shows"prog.invmap id id P = P" and"prog.invmap (λx. x) (λx. x) P = P" by (transfer; simp add: spec.invmap.id id_def)+
lemma comp: shows"prog.invmap sf vf (prog.invmap sg vg P) = prog.invmap (λs. sg (sf s)) (λs. vg (vf s)) P" (is"?thesis1 P") and"prog.invmap sf vf ∘ prog.invmap sg vg = prog.invmap (sg ∘ sf) (vg ∘ vf)" (is"?thesis2") proof - show"?thesis1 P"for P by transfer (simp add: spec.invmap.comp id_def) thenshow ?thesis2 by (simp add: comp_def) qed
lemma monotone: shows"mono (prog.invmap sf vf)" unfolding monotone_def by transfer (simp add: spec.invmap.mono)
lemma Sup: fixes sf :: "'s ==> 't" fixes vf :: "'v ==> 'w" shows"prog.invmap sf vf (⊔X) = ⊔(prog.invmap sf vf ` X) ⊔ prog.invmap sf vf ⊥" by transfer
(simp add: spec.invmap.bot spec.invmap.Sup spec.invmap.sup spec.invmap.bind spec.invmap.rel
spec.interference.cl.bot map_prod_vimage_Times ac_simps
sup.absorb2 spec.bind.mono[OF spec.rel.mono order.refl]
flip: spec.bind.botR spec.bind.bind spec.rel.unwind_bind_trailing bot_fun_def inv_image_alt_def)
lemma Sup_not_empty: assumes"X ≠ {}" shows"prog.invmap sf vf (⊔X) = ⊔(prog.invmap sf vf ` X)" using iffD2[OF ex_in_conv assms] by (clarsimp simp: prog.invmap.Sup sup.absorb1 SUPI prog.invmap.mono[OF bot_least])
lemma mcont: shows"mcont Sup (≤) Sup (≤) (prog.invmap sf vf)" by (simp add: contI mcontI prog.invmap.monotone prog.invmap.Sup_not_empty)
lemmas mcont2mcont[cont_intro] = mcont2mcont[OF prog.invmap.mcont, of luba orda P for luba orda P]
lemma bind: shows"prog.invmap sf vf (f 🍋 g) = prog.sinvmap sf f 🍋 (λv. prog.invmap sf vf (g v))" by transfer (simp add: spec.invmap.bind)
lemma parallel: shows"prog.invmap sf vf (P ∥ Q) = prog.invmap sf vf P ∥ prog.invmap sf vf Q" by transfer (simp add: spec.invmap.parallel)
lemma invmap_image_vimage_commute: shows"map_prod id (map_prod id sf) -` map_prod id (Pair self) ` F = map_prod id (Pair self) ` map_prod id sf -` F" by (auto simp: map_prod_conv)
lemma action: shows"prog.invmap sf vf (prog.action F) = prog.rel (map_prod sf sf -` Id) 🍋 (λ_::unit. prog.action (map_prod id (map_prod sf sf) -` F) 🍋 (λv. prog.rel (map_prod sf sf -` Id) 🍋 (λ_::unit. ⊔v'∈vf -` {v}. prog.return v')))" proof - have *: "{env} × UNIV ∪ {self} × map_prod sf sf -` Id = {env} × UNIV ∪ UNIV × map_prod sf sf -` Id"by auto show ?thesis by (simp add: ac_simps prog.p2s.simps prog.p2s.action
spec.interference.cl.action spec.invmap.bind spec.invmap.rel spec.invmap.action spec.invmap.return
spec.bind.bind spec.bind.return
prog.invmap.invmap_image_vimage_commute map_prod_vimage_Times *
flip: prog.p2s_inject)
(simp add: prog.p2s.Sup image_image prog.p2s.simps prog.p2s.return spec.interference.cl.return
spec.interference.cl.bot spec.bind.supR
spec.rel.wind_bind_leading spec.rel.wind_bind_trailing
flip: spec.bind.botR spec.bind.SUPR spec.bind.bind) qed
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "vmap"›
lemma bot: shows"prog.vmap vf ⊥ = ⊥" by transfer
(simp add: spec.interference.cl.bot spec.vmap.unit_rel
flip: spec.term.none.map_gen[where vf="⟨()⟩"])
lemma unitL: shows"f 🍋 g = prog.vmap ⟨()⟩ f 🍋 g" by transfer (metis spec.vmap.unitL)
lemma eq_return: shows"prog.vmap vf P = P 🍋 prog.return ∘ vf" (is ?thesis1) and"prog.vmap vf P = P 🍋 (λv. prog.return (vf v))" (is ?thesis2) proof - show ?thesis1 by transfer
(simp add: comp_def spec.vmap.eq_return spec.interference.cl.return spec.interference.closed.bind_relR) thenshow ?thesis2 by (simp add: comp_def) qed
lemma action: shows"prog.vmap vf (prog.action F) = prog.action (map_prod vf id ` F)" by transfer (simp add: spec.map.interference.cl_sf_id spec.map.surj_sf_action image_comp)
interpretation kleene: kleene "prog.return ()""λx y. prog.bind x ⟨y⟩" by standard
(simp_all add: prog.bind.bind prog.bind.return prog.bind.botL prog.bind.supL prog.bind.supR)
interpretation rel: galois.complete_lattice_class prog.steps prog.rel proof show"prog.steps P ⊆ r ⟷ P ≤ prog.rel r"for P :: "('a, 'b) prog"and r :: "'a rel" by transfer (auto simp flip: spec.rel.galois) qed
lemma split_vinvmap: fixes P :: "('s, 'v) prog" shows"prog.invmap sf vf P = prog.sinvmap sf P 🍋 (λv. ⊔v'∈vf -` {v}. prog.return v')" proof - note sic_invmap = spec.interference.closed.invmap[where af=id and r="{env} × UNIV",
simplified map_prod_vimage_Times, simplified] show ?thesis apply transfer apply (simp add: spec.bind.supR sup.absorb1 spec.interference.cl.bot bot_fun_def
spec.interference.closed.bind_relR sic_invmap spec.bind.mono
flip: spec.bind.botR) apply (subst (1) spec.invmap.split_vinvmap) apply (subst (1) spec.interference.closed.bind_relR[symmetric], erule sic_invmap) apply (simp add: spec.bind.SUPR spec.bind.supR spec.interference.cl.return
sup.absorb1 bot_fun_def spec.interference.closed.bind_relR sic_invmap spec.bind.mono) done qed
setup‹Sign.parent_path›
setup‹Sign.parent_path›
subsection‹ Refinement for 🪙‹('s, 'v) prog›\label{sec:programs-refinement} ›
text‹
specialize the rules of \S\ref{sec:refinement-spec} to the 🍋‹('s, 'v) prog› lattice. Observe that, as
, postconditions and assumes are not interference closed,
apply the const‹prog.p2s› morphism and work in the more 🍋‹(sequential, 's, 'v) spec›
. This syntactic noise could be elided with another definition.
lemma"if": assumes"i ==> prog.p2s t ≤{P}, A ⊨!!! prog.p2s t', {Q}" assumes"¬i ==> prog.p2s e ≤{P'}, A ⊨!!! prog.p2s e', {Q}" shows"prog.p2s (if i then t else e) ≤{if i then P else P'}, A ⊨!!! prog.p2s (if i then t' else e'), {Q}" using assms by fastforce
lemmasif' = refinement.prog.if[where P=P and P'=P, simplified] for P
lemma case_option: assumes"opt = None ==> prog.p2s none ≤{Pn}, A ⊨!!! prog.p2s none', {Q}" assumes"∧v. opt = Some v ==> prog.p2s (some v) ≤{Ps v}, A ⊨!!! prog.p2s (some' v), {Q}" shows"prog.p2s (case_option none some opt) ≤{case opt of None ==> Pn | Some v ==> Ps v}, A ⊨!!! prog.p2s (case_option none' some' opt), {Q}" using assms by (simp add: option.case_eq_if)
lemma case_sum: assumes"∧v. x = Inl v ==> prog.p2s (left v) ≤{Pl v}, A ⊨!!! prog.p2s (left' v),{Q}" assumes"∧v. x = Inr v ==> prog.p2s (right v) ≤{Pr v}, A ⊨!!! prog.p2s (right' v), {Q}" shows"prog.p2s (case_sum left right x) ≤{case_sum Pl Pr x}, A ⊨!!! prog.p2s (case_sum left' right' x), {Q}" using assms by (simp add: sum.case_eq_if)
lemma case_list: assumes"x = [] ==> prog.p2s nil ≤{Pn}, A ⊨!!! prog.p2s nil', {Q}" assumes"∧v vs. x = v # vs ==> prog.p2s (cons v vs) ≤{Pc v vs}, A ⊨!!! prog.p2s (cons' v vs), {Q}" shows"prog.p2s (case_list nil cons x) ≤{case_list Pn Pc x}, A ⊨!!! prog.p2s (case_list nil' cons' x), {Q}" using assms by (simp add: list.case_eq_if)
lemma return: assumes sQ: "stable (spec.steps A `` {env}) (Q v)" shows"prog.p2s (prog.return v) ≤{Q v}, A ⊨!!! prog.p2s (prog.return v), {Q}" unfolding prog.return_def using assms by (blast intro: refinement.prog.action)
lemma invmap_return: assumes sQ: "stable (spec.steps A `` {env}) (Q v)" assumes"vf v = v'" shows"prog.p2s (prog.return v) ≤{Q v}, A ⊨!!! prog.p2s (prog.invmap sf vf (prog.return v')), {Q}" unfolding prog.invmap.return by (strengthen ord_to_strengthen(2)[OF prog.return.rel_le])
(simp add: assms(2) refinement.pre_g[OF refinement.prog.return[where Q=Q, OF sQ]]
SUP_upper prog.bind.return prog.p2s.mono)
lemma bind_abstract: fixes f :: "('s, 'v) prog" fixes f' :: "('s, 'v') prog" fixes g :: "'v ==> ('s, 'w) prog" fixes g' :: "'v' ==> ('s, 'w) prog" fixes vf :: "'v ==> 'v'" assumes"∧v. prog.p2s (g v) ≤{Q' (vf v)}, refinement.spec.bind.res (spec.pre P ⊓ spec.term.all A ⊓ prog.p2s f') A (vf v) ⊨!!! prog.p2s (g' (vf v)), {Q}" assumes"prog.p2s f ≤{P}, spec.term.all A ⊨!!! spec.vinvmap vf (prog.p2s f'), {λv. Q' (vf v)}" shows"prog.p2s (f 🍋 g) ≤{P}, A ⊨!!! prog.p2s (f' 🍋 g'), {Q}" by (simp add: prog.p2s.simps refinement.spec.bind_abstract[OF assms])
lemma bind: assumes"∧v. prog.p2s (g v) ≤{Q' v}, refinement.spec.bind.res (spec.pre P ⊓ spec.term.all A ⊓ prog.p2s f') A v ⊨!!! prog.p2s (g' v), {Q}" assumes"prog.p2s f ≤{P}, spec.term.all A ⊨!!! prog.p2s f', {Q'}" shows"prog.p2s (f 🍋 g) ≤{P}, A ⊨!!! prog.p2s (f' 🍋 g'), {Q}" by (simp add: prog.p2s.simps refinement.spec.bind[OF assms])
lemmas rev_bind = refinement.prog.bind[rotated]
lemma Parallel: fixes A :: "(sequential, 's, unit) spec" fixes Q :: "'a ==> 's pred" fixes Ps :: "'a ==> ('s, unit) prog" fixes Ps' :: "'a ==> ('s, unit) prog" assumes"∧a. a ∈ as ==> prog.p2s (Ps a) ≤{P a}, refinement.spec.env_hyp P A as (prog.p2s ∘ Ps') a ⊨!!! prog.p2s (Ps' a), {λrv. Q a}" shows"prog.p2s (prog.Parallel as Ps) ≤{⊓a∈as. P a}, A ⊨!!! prog.p2s (prog.Parallel as Ps'), {λrv. ⊓a∈as. Q a}" using assms by transfer (simp add: refinement.spec.Parallel comp_def)
lemma parallel: assumes"prog.p2s c1≤{P1}, refinement.spec.env_hyp (λa. if a then P1 else P2) A UNIV (λa. if a then prog.p2s c1' else prog.p2s c2') True ⊨!!! prog.p2s c1', {Q1}" assumes"prog.p2s c2≤{P2}, refinement.spec.env_hyp (λa. if a then P1 else P2) A UNIV (λa. if a then prog.p2s c1' else prog.p2s c2') False ⊨!!! prog.p2s c2', {Q2}" shows"prog.p2s (prog.parallel c1 c2) ≤{P1\<and> P2}, A ⊨!!! prog.p2s (prog.parallel c1' c2'), {λv. Q1 v \<and> Q2 v}" unfolding prog.parallel_alt_def by (rule refinement.pre[OF refinement.prog.Parallel[where A="A"and P="λa. if a then P1 else P2"and Ps'="λa. if a then c1' else c2'"and Q="λa. if a then Q1 () else Q2 ()"]])
(use assms in‹force simp: if_distrib comp_def›)+
setup‹Sign.parent_path›
subsection‹ A relational assume/guarantee program logic for the 🪙‹('s, 'v) prog› lattice\label{sec:programs-ag} ›
text‹
we specialize the assume/guarantee program logic of
S\ref{sec:refinement-ag} to 🍋‹('s, 'v) prog›.
:
▪ 🍋‹"XudeRoeverHe:1997" and "deRoeverEtAl:2001"›
▪ 🍋‹‹\S7› in "PrensaNieto:2003"›
▪ 🍋‹‹\S3› in "Vafeiadis:2008"›
suitably stable ‹P›, ‹Q›, ‹{P}, A ⊨ G, {Q}› is interference closed and hence denotes a
in 🍋‹('s, 'v) prog›. In other words we can replace programs with their specifications.
›
setup‹Sign.mandatory_path "ag.prog"›
lemma galois: shows"prog.p2s c ≤{P}, A ⊨ G, {Q}⟷ c ≤ prog.s2p ({P}, A ⊨ G, {Q})" by (simp add: prog.p2s_s2p.galois ag.spec.term.none_inteference)
lemmas s2p_ag = iffD1[OF ag.prog.galois]
lemma p2s_s2p_ag: shows"prog.p2s (prog.s2p ({P}, A ⊨ G, {Q})) ≤{P}, A ⊨ G, {Q}" by (simp add: ag.prog.galois)
lemma p2s_s2p_ag_stable: assumes"stable A P" assumes"∧v. stable A (Q v)" shows"prog.p2s (prog.s2p ({P}, A ⊨ G, {Q})) = {P}, A ⊨ G, {Q}" by (rule prog.p2s_s2p.insertion[OF spec.interference.closed_ag[where r=UNIV, simplified, OF assms]])
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "prog.ag"›
lemma bot[iff]: shows"prog.p2s ⊥≤{P}, A ⊨ G, {Q}" by (simp add: ag.prog.galois)
setup‹Sign.parent_path›
setup‹Sign.mandatory_path "ag"›
setup‹Sign.mandatory_path "prog"›
lemma sup_conv: shows"prog.p2s (c1⊔ c2) ≤{P}, A ⊨ G, {Q}⟷ prog.p2s c1≤{P}, A ⊨ G, {Q}∧ prog.p2s c2≤{P}, A ⊨ G, {Q}" by (simp add: prog.p2s.simps)
lemma bind: ―‹ Assumptions in weakest-pre order › assumes"∧v. prog.p2s (g v) ≤{Q' v}, A ⊨ G, {Q}" assumes"prog.p2s f ≤{P}, A ⊨ G, {Q'}" shows"prog.p2s (f 🍋 g) ≤{P}, A ⊨ G, {Q}" by (simp add: prog.p2s.simps) (rule ag.spec.bind; fact)
lemma action: ―‹ Conclusion is insufficiently instantiated for use › fixes F :: "('v × 's × 's) set" assumes Q: "∧v s s'. [P s; (v, s, s') ∈ F]==> Q v s'" assumes G: "∧v s s'. [P s; s ≠ s'; (v, s, s') ∈ F]==> (s, s') ∈ G" assumes sP: "stable A P" assumes sQ: "∧s s' v. [P s; (v, s, s') ∈ F]==> stable A (Q v)" shows"prog.p2s (prog.action F) ≤{P}, A ⊨ G, {Q}" unfolding prog.p2s.action spec.interference.cl.action ―‹ sp proof › by (rule ag.gen_asm
ag.spec.bind[rotated] ag.spec.stable_interference ag.spec.return
ag.spec.action[where Q="λv s. Q v s ∧ (∃s s'. P s ∧ (v, s, s') ∈ F)"]
| use assms in auto)+
lemma guard: assumes"∧s. [P s; g s]==> Q () s" assumes"stable A P" assumes"stable A (Q ())" shows"prog.p2s (prog.guard g) ≤{P}, A ⊨ G, {Q}" using assms by (fastforce simp: prog.guard_def intro: ag.prog.action split: if_splits)
lemma Parallel: assumes"∧a. a ∈ as ==> prog.p2s (Ps a) ≤{P a}, A ∪ (∪a'∈as-{a}. G a') ⊨ G a, {λv. Q a}" shows"prog.p2s (prog.Parallel as Ps) ≤{⊓a∈as. P a}, A ⊨∪a∈as. G a, {λv. ⊓a∈as. Q a}" using assms by transfer (fast intro: ag.spec.Parallel)
lemma parallel: assumes"prog.p2s c1≤{P1}, A ∪ G2⊨ G1, {Q1}" assumes"prog.p2s c2≤{P2}, A ∪ G1⊨ G2, {Q2}" shows"prog.p2s (prog.parallel c1 c2) ≤{P1\<and> P2}, A ⊨ G1∪ G2, {λv. Q1 v \<and> Q2 v}" unfolding prog.parallel_alt_def by (rule ag.pre[OF ag.prog.Parallel[where A="A"and G="λa. if a then G1 else G2"and P="⟨P1\<and> P2⟩"and Q="λa. if a then Q1 () else Q2 ()"]])
(use assms in‹auto intro: ag.pre_imp›)
lemma return: assumes sQ: "stable A (Q v)" shows"prog.p2s (prog.return v) ≤{Q v}, A ⊨ G, {Q}" using assms by (auto simp: prog.return_def intro: ag.prog.action)
lemma"if": assumes"b ==> prog.p2s c1≤{P1}, A ⊨ G, {Q}" assumes"¬b ==> prog.p2s c2≤{P2}, A ⊨ G, {Q}" shows"prog.p2s (if b then c1 else c2) ≤{if b then P1 else P2}, A ⊨ G, {Q}" using assms by (fastforce intro: ag.pre_ag)
lemma case_option: assumes"x = None ==> prog.p2s none ≤{Pn}, A ⊨ G, {Q}" assumes"∧v. x = Some v ==> prog.p2s (some v) ≤{Ps v}, A ⊨ G, {Q}" shows"prog.p2s (case_option none some x) ≤{case x of None ==> Pn | Some v ==> Ps v}, A ⊨ G, {Q}" using assms by (fastforce intro: ag.pre_ag split: option.split)
lemma case_sum: assumes"∧v. x = Inl v ==> prog.p2s (left v) ≤{Pl v}, A ⊨ G, {Q}" assumes"∧v. x = Inr v ==> prog.p2s (right v) ≤{Pr v}, A ⊨ G, {Q}" shows"prog.p2s (case_sum left right x) ≤{case_sum Pl Pr x}, A ⊨ G, {Q}" using assms by (fastforce intro: ag.pre_ag split: sum.split)
lemma case_list: assumes"x = [] ==> prog.p2s nil ≤{Pn}, A ⊨ G, {Q}" assumes"∧v vs. x = v # vs ==> prog.p2s (cons v vs) ≤{Pc v vs}, A ⊨ G, {Q}" shows"prog.p2s (case_list nil cons x) ≤{case_list Pn Pc x}, A ⊨ G, {Q}" using assms by (fastforce intro: ag.pre_ag split: list.split)
setup‹Sign.parent_path›
setup‹Sign.parent_path›
subsubsection‹ A proof of the parallel rule using Abadi and Plotkin's composition principle\label{sec:abadi_plotkin-parallel} ›
text‹
we show that the key rule for const‹prog.Parallel› (@{thm [source] "ag.spec.Parallel"})
be established using the @{thm [source] "spec.ag_circular"} rule (\S\ref{sec:abadi_plotkin}).
following proof is complicated by the need to discard a lot of
information.
›
notepad begin
have imp_discharge_leL1: "x' ≤ x ==> x' ⊓ (x ⊓ y \<longrightarrow>H z) = x' ⊓ (y \<longrightarrow>H z)"for x x' y z by (simp add: heyting.curry_conv heyting.discharge(1))
have LHS_rel: "{proc x} × UNIV ∪ (-{proc x}) × (A ∪ (Id ∪∪ (G ` (as - {x})))) = ((-(proc ` as)) × (A ∪ (Id ∪∪ (G ` (as - {x})))) ∪ ({proc x} × UNIV ∪ proc ` (as - {x}) × (A ∪ (Id ∪∪ (G ` (as - {x}))))))"for A G as x by blast
have rel_agents_split: "spec.rel (as × r ∪ s) = spec.rel (as × r ∪ fst ` s × UNIV) ⊓ spec.rel (as × UNIV ∪ s)" if"fst ` s ∩ as = {}"for as r s using that by (fastforce simp: image_iff simp flip: spec.rel.inf intro: arg_cong[where f="spec.rel"])
―‹ @{thm [source] ag.spec.Parallel} › fix as :: "'a set" fix A :: "'s rel" fix G :: "'a ==> 's rel" fix P :: "'a ==> 's pred" fix Q :: "'a ==> 's pred" fix Ps :: "'a ==> (sequential, 's, unit) spec" assume proc_ag: "∧a. a ∈ as ==> Ps a ≤{P a}, A ∪ (∪a'∈as-{a}. G a') ⊨ G a, {λv. Q a}" have"spec.Parallel as Ps ≤{⊓a∈as. P a}, A ⊨∪a∈as. G a, {λv. ⊓a∈as. Q a}" (is"?lhs ≤ ?rhs") proof(cases "as = {}") case True thenshow ?thesis by (simp add: spec.Parallel.no_agents ag.interference_le) next case False thenshow ?thesis apply -
supply inf.bounded_iff[simp del] ―‹ preserve RHS ›
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.