demonstrate assume/guarantee reasoning by showing the safety of ‹findP›, a classic exercise in
verification. It has been treated by at least:
▪🚫‹‹Example~5.1› in "KarpMiller:1969"› ▪🚫‹‹\S3› in "Rosen:1976"› ▪🚫‹‹\S4 Example~2› in "OwickiGries:1976"› ▪🚫‹‹\S2.4› in "Jones:1983"› ▪🚫‹‹\S3.1› in "XuCauCollette:1994"› ▪🚫‹‹p161› in "Brookes:1996"› (no proof) ▪🚫‹‹Examples~3.57~and~8.26› in "deRoeverEtAl:2001"› (atomic guarded commands) ▪🚫‹‹\S6.2› in "Dingel:2002"› (refinement) ▪🚫‹‹\S10› in "PrensaNieto:2003"› (mechanized, arbitrary number of threads) ▪🚫‹‹\S7.4, \S8.6› in "AptDeBoerOlderog:2009"› ▪🚫‹‹\S4› in "HayesJones:2017"› (refinement)
take the task to be of finding the first element of a given ‹A› that satisfies a given predicate ‹pred›, if it exists, or yielding ‹length A›
it does not. This search is performed with two threads: one
the even indices and the other the odd. There is the
of a thread terminating early if it notices that the other
has found a better candidate than it could.
generalise previous treatments by allowing the predicate to be
modularly and to be a function of the state. It is required
be pure, i.e., it cannot change the observable/shared state, though
could have its own local state.
search loops are defined recursively; one could just as easily use const‹prog.while›. We use a list and not an array for
-- at this level of abstraction there is no difference --
a mix of variables, where the monadic ones are purely local and
state-based are shared between the threads. The lens allows the
to be a value or reside in the (observable/shared) state.
› (* The program and proofs should carry over to TSO directly: the assume is already strong enough. *)
context fixes pred :: "'a → ('s, bool) prog" fixes predPre :: "'s pred" fixes predP :: "'a → 's pred" fixes A :: "'s rel" fixes array :: "'a list ==> 's" ―‹ A guarantee of ‹Id› indicates that ‹pred a› is observationally pure. › assumes iag_pred: "∧a. prog.p2s (pred a) ≤{predPre \<and> ⟨a⟩\<in> SET get}, A=∩ Id∩ ceilr predPre ∩ Id a⊨ Id, {λrv. ⟨rv⟩= predP a}" begin
abbreviation array' :: "'a list ==> 's state" where "array' ≡ array ;L sndL"
partial_function (lfp) findP_loop_evens :: "nat → ('s state, unit) prog" where "findP_loop_evens i = do { fO ← prog.read get ; prog.whenM (i < fO) (do { v ← prog.read (λs. get' s ! i) ; b ← prog.localize (pred v) ; if b then prog.write (λs. put s i) else findP_loop_evens (i + 2) }) }"
partial_function (lfp) findP_loop_odds :: "nat → ('s state, unit) prog" where "findP_loop_odds i = do { fE ← prog.read get ; prog.whenM (i < fE) (do { v ← prog.read (λs. get' s ! i) ; b ← prog.localize (pred v) ; if b then prog.write (λs. put s i) else findP_loop_odds (i + 2) }) }"
definition findP :: "('s, nat) prog" where "findP = prog.local ( do { N ← prog.read (SIZE get') ; prog.write (λs. put s N) ; prog.write (λs. put s N) ; (findP_loop_evens 0 ∥ findP_loop_odds 1) ; fE ← prog.read (get) ; fO ← prog.read (get) ; prog.return (min fE fO) })"
paragraph‹ Relies and guarantees ›
abbreviation (input) A' :: "'s rel" where "A' ≡ A=∩ ceilr predPre ∩ (∩a. Id a)"
definition AE :: "'s state rel" where "AE = UNIV ×R A' ∩ Id'∩ Id∩\<le>"
definition GE :: "'s state rel" where "GE = Id∩ Id∩\<le>"
definition AO :: "'s state rel" where "AO = UNIV ×R A' ∩ Id'∩ Id∩\<le>"
definition GO :: "'s state rel" where "GO = Id∩ Id∩\<le>"
lemma AG_refl_trans: shows "refl AE" "refl AO" "trans A ==> trans AE" "trans A ==> trans AO" "refl GE" "refl GO" "trans GE" "trans GO" unfolding AE_def AO_def GE_def GO_def by (auto simp: refl_inter_conv refl_relprod_conv
intro!: trans_Int refl_UnionI refl_INTER trans_INTER)
theorem ag_findP: shows"prog.p2s findP ≤{predPre}, A' ∩ Id ⊨ Id, {λv s. v = (LEAST i. i < SIZE get s ⟶ predP (get s ! i) s)}" unfolding findP_def apply (rule ag.prog.local) apply (rule iag.init) apply (rule iag.intro)+ apply (rule iag.augment_post_imp[where Q="λv. get\<le> SIZE get'\<and> get\<le> SIZE get'"]) apply (rule iag.pre_g[OF _ G_containment]) apply (rule iag.stable_augment_frame) apply (rule iag.parallel[OF ag_findP_loop_evens ag_findP_loop_odds _ AG_containment order.refl]) ―‹ postcondition from ‹iag.parallel›› apply clarsimp apply (rule Least_equality, linarith) subgoalfor x y s z by (clarsimp simp: min_le_iff_disj not_less not_le dest!: spec[where x=z]) ―‹ stability for ‹iag.stable_augment_frame›› apply (force simp: stable_def monotone_def AE_def AO_def GE_def GO_def) apply (rule iag.intro)+ ―‹ precondition › apply fastforce ―‹ assume › apply (simp;
intro conjI Int_greatest INT_greatest ceilr.largest;
fastforce simp: AE_def AO_def stable_def monotone_def) done
end
text‹
conclude by showing how we can instantiate the above with a ‹coprime› predicate.
›
setup‹Sign.mandatory_path "gcd"›
type_synonym 's state = "(nat × nat) × 's"
abbreviation x :: "nat ==> 's gcd.state" where "x ≡ fstL ;L fstL" abbreviation y :: "nat ==> 's gcd.state" where "y ≡ sndL ;L fstL"
definition seq :: "nat → nat → ('s, nat) prog" where "seq a b = prog.local ( do { prog.write (λs. put.x s a) ; prog.write (λs. put.y s b) ; prog.while (λ_. do { xv ← prog.read get.x ; yv ← prog.read get.y ; if xv = yv then prog.return (Inr ()) else (do { (if xv < yv then prog.write (λs. put.y s (yv - xv)) else prog.write (λs. put.x s (xv - yv))) ; prog.return (Inl ()) }) }) () ; prog.read get.x })"
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.