From c4f43fd8dcbe8d25540b04f6a9f97cb5f6f6cf75 Mon Sep 17 00:00:00 2001 From: Thomas Sewell Date: Mon, 28 May 2018 15:38:19 +1000 Subject: [PATCH] lib: two examples of concurrency reasoning. Two different simple examples which make use of the prefix refinement framework and the rely-guarantee VCG. --- .../examples/Peterson_Atomicity.thy | 839 ++++++++++++++++++ lib/concurrency/examples/Plus2_Prefix.thy | 256 ++++++ 2 files changed, 1095 insertions(+) create mode 100644 lib/concurrency/examples/Peterson_Atomicity.thy create mode 100644 lib/concurrency/examples/Plus2_Prefix.thy diff --git a/lib/concurrency/examples/Peterson_Atomicity.thy b/lib/concurrency/examples/Peterson_Atomicity.thy new file mode 100644 index 000000000..f4dd05ea5 --- /dev/null +++ b/lib/concurrency/examples/Peterson_Atomicity.thy @@ -0,0 +1,839 @@ +(* + * Copyright 2017, Data61, CSIRO + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + *) +theory Peterson_Atomicity +imports + "../Atomicity_Lib" +begin + +text {* + Preliminaries, a type of identities. +*} + +datatype ident = A | B + +primrec other_ident +where + "other_ident A = B" + | "other_ident B = A" + +lemma other_ident_split: + "P (other_ident x) = ((x = A \ P B) \ (x = B \ P A))" + by (cases x, simp_all) + +lemma neq_A_B[simp]: + "(x \ A) = (x = B)" + "(A \ x) = (x = B)" + "(x \ B) = (x = A)" + "(B \ x) = (x = A)" + by (simp | cases x)+ + +lemma forall_ident_eq: + "(\ident. P ident) = (P A \ P B)" + using ident.nchotomy + by metis + +lemma other_other_ident_simps[simp]: + "other_ident (other_ident x) = x" + "(other_ident x = y) = (x \ y)" + "(x = other_ident y) = (x \ y)" + by (simp_all split: other_ident_split add: eq_commute) + +text {* +The state of the algorithm. The variables A/B are condensed into +an ab_v variable, so we can parametrise by thread A/B. The priority +variable is t_v, and the critical section cs has two variable to +operate on, cs1_v and cs2_v. + +Labels are needed to track where we're up to for the preconditions, +relies and guarantees. +*} + +datatype label = Awaiting | Critical | Exited + +record ('a, 'b) p_state = + ab_v :: "ident \ bool" + ab_label :: "ident \ label" + t_v :: "ident" + cs1_v :: "'a" + cs2_v :: "'b" + +locale mx_locale = + fixes cs1 :: "'b \ 'a" + and cs2 :: "(('a, 'b) p_state, unit) tmonad" + and csI :: "'b \ bool" +begin + +definition + set_ab :: "ident \ bool \ ('a, 'b) p_state \ ('a, 'b) p_state" +where + "set_ab ident trying s = (s \ ab_v := (ab_v s) (ident := trying) \)" + +definition + set_label :: "ident \ label \ ('a, 'b) p_state \ ('a, 'b) p_state" +where + "set_label ident label s = (s \ ab_label := (ab_label s) (ident := label) \)" + +definition + locked :: "ident \ ('a, 'b) p_state \ bool" +where + "locked ident s = (ab_v s (other_ident ident) \ t_v s = ident)" + +definition + acquire_lock :: "ident \ (('a, 'b) p_state, unit) tmonad" +where + "acquire_lock ident = do + interference; + modify (set_ab ident True); + modify (\s. s \ t_v := other_ident ident \); + modify (set_label ident Awaiting); + interference; + Await (locked ident); + modify (set_label ident Critical) + od" + +definition + release_lock :: "ident \ (('a, 'b) p_state, unit) tmonad" +where + "release_lock ident = do + modify (set_ab ident False); + modify (set_label ident Exited); + interference; + return () + od" + +definition + abs_critical_section :: "(('a, 'b) p_state, unit) tmonad" +where + "abs_critical_section = do + interferences; + modify (\s. s \ cs1_v := cs1 (cs2_v s) \); + cs2; + interference + od" + +definition + abs_peterson_proc :: + "ident \ (('a, 'b) p_state, unit) tmonad" +where + "abs_peterson_proc ident = do + acquire_lock ident; + abs_critical_section; + release_lock ident + od" + +definition + critical_section :: "(('a, 'b) p_state, unit) tmonad" +where + "critical_section = do + interference; + modify (\s. s \ cs1_v := cs1 (cs2_v s) \); + interference; + cs2; + interference + od" + +definition + peterson_proc :: "ident \ (('a, 'b) p_state, unit) tmonad" +where + "peterson_proc ident = do + acquire_lock ident; + critical_section; + release_lock ident + od" + +abbreviation "critical label \ label = Critical" + +text {* The required invariant. We can't both be in the critical section. +Whenever neither of us is in the critical section, its invariant holds. *} +definition + req_peterson_inv :: "('a, 'b) p_state \ bool" +where + "req_peterson_inv s = (\ (critical (ab_label s A) \ critical (ab_label s B)) + \ (critical (ab_label s A) \ critical (ab_label s B) \ csI (cs2_v s)))" + +text {* The key invariant. We can't both be enabled, where that means +either we're in the critical section or waiting to enter with priority. +*} +abbreviation(input) + enabled :: "ident \ ('a, 'b) p_state \ bool" +where + "enabled ident s \ (critical (ab_label s ident) + \ (ab_label s ident = Awaiting \ t_v s = ident))" + +definition + key_peterson_inv :: "('a, 'b) p_state \ bool" +where + "key_peterson_inv s = (\ (enabled A s \ enabled B s))" + +text {* Some trivia about labels and variables. *} +definition + local_peterson_inv :: "('a, 'b) p_state \ bool" +where + "local_peterson_inv s + = (\ident. ab_label s ident \ Exited \ ab_v s ident)" + +definition + "invs s = (req_peterson_inv s + \ key_peterson_inv s \ local_peterson_inv s)" + +lemmas invs_defs = req_peterson_inv_def key_peterson_inv_def local_peterson_inv_def + +definition + peterson_rel :: "ident \ ('a, 'b) p_state \ ('a, 'b) p_state \ bool" +where + "peterson_rel ident s_prior s = ((* assume invs *) invs s_prior \ + (* invariants are preserved *) + (invs s + (* I won't adjust your variables *) + \ (ab_v s (other_ident ident) = ab_v s_prior (other_ident ident)) + \ (ab_label s (other_ident ident) = ab_label s_prior (other_ident ident)) + (* I will only ever give you priority *) + \ (t_v s_prior = other_ident ident \ t_v s = other_ident ident) + (* If you're in the critical section, I won't change cs2_v and cs1_v *) + \ (critical (ab_label s_prior (other_ident ident)) + \ cs2_v s = cs2_v s_prior \ cs1_v s = cs1_v s_prior) + ))" + +lemma peterson_rel_rtranclp[simp]: + "rtranclp (peterson_rel ident) = (peterson_rel ident)" + apply (rule rtranclp_id2) + apply (clarsimp simp: peterson_rel_def) + apply (clarsimp simp: peterson_rel_def) + done + +lemma reflp_peterson_rel[simp]: + "reflp (peterson_rel x)" + apply (rule reflpI) + apply (clarsimp simp add: peterson_rel_def) + done +declare reflp_peterson_rel[THEN reflpD, simp] + +lemma peterson_rel_imp_assume_invs: + "invs x \ (peterson_rel ident x y \ invs x \ invs y \ P x y) + \ (peterson_rel ident x y \ P x y)" + by (simp add: peterson_rel_def) + +end + +text {* +We assume validity for the underspecified critical section code represented by +@{text cs2}. + +We also assume some basic sanity properties about the structure of @{text cs2}. +*} +locale mx_locale_wp = mx_locale cs1 cs2 csI for cs1 :: "'b \ 'a" and cs2 and csI + + assumes + cs_wp: "\s c. I s \ lockf s \ I s \ lockf (s \ cs2_v := c \) + \ + \ \s0' s'. csI (cs2_v s') \ s0' = s0 \ s' = s \ I s \ lockf s + \ cs1_v s' = cs1 (cs2_v s') \, + \ \s0 s. I s0 \ lockf s0 \ cs2_v s = cs2_v s0 \ I s \ lockf s + \ cs1_v s = cs1_v s0 \ + cs2 + \ \s0 s. I s0 \ (\c. s = s0 \ cs2_v := c \) \ I s \ lockf s \, + \ \_ s0' s'. \c. csI c \ s' = s \ cs2_v := c \ + \ (\c'. s0' = s0 \ s0' = s \ cs2_v := c' \) + \ I s' \ lockf s' \" + and cs_closed: "prefix_closed cs2" + and cs_not_env_steps_first: "not_env_steps_first cs2" +begin + +method_setup rev_drule = {* + Attrib.thms >> curry (fn (thms, ctxt) + => SIMPLE_METHOD (dresolve_tac ctxt thms 1 #> Seq.list_of #> rev #> Seq.of_list)) +*} + +lemma cs2_wp_apply_peterson[wp]: + "\ (\s0 s. csI (cs2_v s) + \ invs s0 \ invs s \ critical (ab_label s ident) + \ cs1_v s = cs1 (cs2_v s) + \ (\s0' c' c. csI c \ (\c'. s0' = s0 \ s0' = s \ cs2_v := c' \) + \ Q () s0' (s \ cs2_v := c\))) \, + \ peterson_rel (other_ident ident) \ + cs2 + \ peterson_rel ident \, + \ Q \" + apply (rule validI_name_pre[OF cs_closed], clarsimp simp del: imp_disjL) + apply (rule validI_weaken_pre) + apply (rule validI_well_behaved[OF cs_closed]) + apply (rule validI_strengthen_post) + apply (rule_tac s=s and ?s0.0=s0 + and lockf="\s. critical (ab_label s ident)" + and I="invs" in cs_wp) + apply (clarsimp simp: invs_defs invs_def) + apply (clarsimp simp del: imp_disjL) + apply (simp only: imp_conjL[symmetric]) + apply (thin_tac "\x. P x" for P) + apply (clarsimp simp: peterson_rel_def) + apply (thin_tac "\x. P x" for P) + apply (clarsimp simp: peterson_rel_def) + apply (cases ident; fastforce simp: invs_def key_peterson_inv_def) + apply clarsimp + done + +lemma release_lock_mutual_excl: + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Critical \ csI (cs2_v s) \, + \ peterson_rel (other_ident ident) \ + release_lock ident + \ peterson_rel ident \, + \ \rv s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \" + apply (simp add: release_lock_def) + apply (rule validI_weaken_pre) + apply wpsimp+ + apply (strengthen peterson_rel_imp_assume_invs | simp)+ + apply (cases ident) + apply (safe, simp_all) + by ((clarsimp simp: peterson_rel_def set_label_def + set_ab_def invs_defs + | rule invs_def[THEN iffD2] conjI + | rev_drule invs_def[THEN iffD1])+) + +lemma abs_critical_section_mutual_excl: + "\ \s0 s. peterson_rel ident s0 s \ invs s \ invs s0 + \ ab_label s ident = Critical \ csI (cs2_v s) \, + \ peterson_rel (other_ident ident) \ + abs_critical_section + \ peterson_rel ident \, + \ \rv s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Critical \ csI (cs2_v s) \" + apply (simp add: abs_critical_section_def) + apply (rule validI_weaken_pre) + apply wpsimp+ + apply (strengthen peterson_rel_imp_assume_invs | simp)+ + apply (cases ident) + apply (safe, simp_all) + by ((clarsimp simp: peterson_rel_def invs_defs + | rule invs_def[THEN iffD2] conjI + | rev_drule invs_def[THEN iffD1])+) + +lemma acquire_lock_mutual_excl: + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + acquire_lock ident + \ peterson_rel ident \, + \ \rv s0 s. peterson_rel ident s0 s \ invs s \ invs s0 + \ ab_label s ident = Critical \ csI (cs2_v s) \" + apply (simp add: acquire_lock_def) + apply (rule validI_weaken_pre) + apply (wpsimp wp: Await_sync_twp)+ + apply (strengthen peterson_rel_imp_assume_invs | simp)+ + apply (cases ident) + apply (safe, simp_all) + by ((clarsimp simp: peterson_rel_def set_label_def set_ab_def + locked_def invs_defs + | rule invs_def[THEN iffD2] conjI + | rev_drule invs_def[THEN iffD1])+) + +theorem abs_peterson_proc_mutual_excl: + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + abs_peterson_proc ident + \ peterson_rel ident \, + \ \rv s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \" + apply (simp add: abs_peterson_proc_def bind_assoc) + apply (rule validI_weaken_pre) + apply (wpsimp wp: release_lock_mutual_excl acquire_lock_mutual_excl + abs_critical_section_mutual_excl)+ + done + +definition + peterson_sr :: "(('a, 'b) p_state \ ('a, 'b) p_state \ bool)" +where + "peterson_sr sa sc \ + t_v sa = t_v sc \ ab_v sa = ab_v sc + \ ab_label sa = ab_label sc \ cs2_v sa = cs2_v sc" + +definition + peterson_sr' :: "(('a, 'b) p_state \ ('a, 'b) p_state \ bool)" +where + "peterson_sr' sa sc \ sa = sc \ cs1_v := cs1_v sa \" + +definition + peterson_sr_cs1 :: "(('a, 'b) p_state \ ('a, 'b) p_state \ bool)" +where + "peterson_sr_cs1 sa sc \ peterson_sr sa sc \ cs1_v sa = cs1_v sc" + +end +text {* +Finally we assume that we can prove refinement for @{text cs2}, although this +may depend on being in a state where @{term cs1_v} has been correctly +initialised. +*} +locale mx_locale_refine = mx_locale_wp cs1 cs2 csI for cs1 :: "'b \ 'a" and cs2 and csI + + assumes + cs_refine: + "prefix_refinement peterson_sr peterson_sr_cs1 peterson_sr \\ + (\_ s. cs1_v s = cs1 (cs2_v s)) \\ + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + cs2 cs2" +begin + +lemma + "peterson_sr = peterson_sr'" + by (auto simp: p_state.splits peterson_sr_def peterson_sr'_def intro!: ext) + +lemma peterson_sr_set_ab[simp]: + "peterson_sr s t \ peterson_sr (set_ab ident v s) (set_ab ident v t)" + by (simp add: peterson_sr_def set_ab_def) + +lemma env_stable_peterson_sr: + "env_stable AR R peterson_sr peterson_sr \" + by (fastforce simp: env_stable_def rely_stable_def env_rely_stable_iosr_def peterson_sr_def) + +lemmas prefix_refinement_interference_peterson = + prefix_refinement_interference[OF env_stable_peterson_sr] + +lemma peterson_sr_reflp[simp]: + "reflp peterson_sr" + by (simp add: peterson_sr_def reflpI) + +lemma peterson_sr_equivp[simp]: + "equivp peterson_sr" + by (auto simp: peterson_sr_def intro!: sympI equivpI transpI) + +lemma peterson_sr_cs1_invs: "peterson_sr_cs1 s t \ invs s = invs t" + apply (auto simp: peterson_sr_def peterson_sr_cs1_def invs_def + req_peterson_inv_def key_peterson_inv_def + local_peterson_inv_def)[1] + done + +lemma env_stable_peterson_sr_cs1: + "env_stable (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + peterson_sr peterson_sr_cs1 (\s. invs s \ critical (ab_label s ident))" + apply (simp add: env_stable_def rely_stable_def env_rely_stable_iosr_def + peterson_rel_def) + apply (rule conjI) + apply (auto simp: peterson_sr_def peterson_sr_cs1_def)[1] + apply (rule conjI) + apply clarsimp + apply (clarsimp simp: peterson_sr_cs1_invs) + apply (auto simp: peterson_sr_cs1_def peterson_sr_def)[1] + apply (auto simp: peterson_sr_cs1_def peterson_sr_def)[1] + done + +lemmas prefix_refinement_interference_peterson_cs1 = + prefix_refinement_interference[OF env_stable_peterson_sr_cs1] + +lemmas prefix_refinement_bind_2left_2right + = prefix_refinement_bind[where a="bind a a'" and c="bind c c'" for a a' c c', simplified bind_assoc] +lemmas rel_tr_refinement_bind_left_general_2left_2right + = rel_tr_refinement_bind_left_general[where f="bind f f'" and g="bind g g'" for f f' g g', simplified bind_assoc] + +lemma peterson_rel_imp_invs: + "peterson_rel ident x y \ invs x \ invs y" + by (simp add: peterson_rel_def) + +lemma peterson_rel_imp_label: + "peterson_rel (other_ident ident) x y \ invs x + \ ab_label x ident = ab_label y ident" + by (simp add: peterson_rel_def) + +lemma peterson_rel_set_label: + "peterson_rel (other_ident ident) (set_label ident label s) s' + \ invs (set_label ident label s) + \ ab_label s' ident = label" + by (simp add: peterson_rel_def set_label_def) + +lemma acquire_lock_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + \\ \\ + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + (acquire_lock ident) (acquire_lock ident)" + apply (unfold acquire_lock_def) + apply (rule prefix_refinement_weaken_pre) + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_interference_peterson) + apply (simp add: modify_modify_bind) + apply (rule prefix_refinement_bind_sr) + apply (rule pfx_refn_modifyT) + apply (clarsimp simp add: peterson_sr_def set_label_def set_ab_def forall_ident_eq) + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_interference_peterson) + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_Await[OF env_stable_peterson_sr abs_rely_stableT]) + apply (clarsimp simp add: peterson_sr_def locked_def) + apply (clarsimp simp add: peterson_sr_def locked_def) + apply (rule pfx_refn_modifyT) + apply (clarsimp simp add: peterson_sr_def set_label_def) + apply (wpsimp wp: Await_sync_twp)+ + done + +lemma peterson_sr_invs[simp]: + "peterson_sr as cs \ invs as \ invs cs" + by (simp add: peterson_sr_def invs_def invs_defs) + +lemma peterson_sr_invs_sym: + "peterson_sr as cs \ invs cs \ invs as" + by (simp add: peterson_sr_def invs_def invs_defs) + +lemma peterson_sr_ab_label: + "peterson_sr as cs \ ab_label as = ab_label cs" + by (simp add: peterson_sr_def) + +lemma critical_section_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + (\_ s. invs s \ ab_label s ident = Critical) \\ + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + abs_critical_section critical_section" + apply (simp add: abs_critical_section_def critical_section_def) + apply (rule prefix_refinement_weaken_pre) + apply (rule prefix_refinement_interferences_split) + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_interference_peterson) + + (* reorder the interference and modify*) + apply (rule pfx_refinement_use_rel_tr_refinement_equivp + [where Q="\s. invs s \ ab_label s (ident) = Critical"]) + apply (rule rel_tr_refinement_bind_left_general_2left_2right) + apply simp + apply (rule disjI1, + clarsimp simp: not_env_steps_first_all + cs_not_env_steps_first release_lock_def) + apply (rule rshuttle_modify_interference) + apply (simp add: peterson_sr_def peterson_rel_def) + apply (clarsimp simp: peterson_rel_def) + apply (clarsimp simp: p_state.splits) + apply (clarsimp simp: peterson_rel_def invs_def invs_defs) + apply simp + + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_interference_peterson) + apply (rule prefix_refinement_bind[where intsr=peterson_sr_cs1]) + apply (rule pfx_refn_modifyT) + apply (clarsimp simp add: peterson_sr_def peterson_sr_cs1_def) + apply (rule prefix_refinement_bind_sr) + apply (rule cs_refine) + apply (rule prefix_refinement_interference_peterson) + + apply (wpsimp wp: validI_triv[OF cs_closed])+ + apply (subst peterson_rel_imp_label[symmetric], assumption, simp) + apply (drule peterson_rel_imp_invs, simp) + apply (simp add: peterson_sr_ab_label) + done + +lemma release_lock_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + \\ \\ + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + (release_lock ident) (release_lock ident)" + apply (unfold release_lock_def) + apply (rule prefix_refinement_weaken_pre) + apply (simp add: modify_modify_bind) + apply (rule prefix_refinement_bind_sr) + apply (rule pfx_refn_modifyT) + apply (clarsimp simp add: peterson_sr_def peterson_sr_cs1_def set_label_def set_ab_def) + apply (rule prefix_refinement_interference_peterson) + apply wpsimp+ + done + +lemma critical_section_prefix_closed[simp]: + "prefix_closed critical_section" + by (auto intro!: prefix_closed_bind + simp: cs_closed critical_section_def) + +lemma abs_critical_section_prefix_closed[simp]: + "prefix_closed abs_critical_section" + by (auto intro!: prefix_closed_bind + simp: cs_closed abs_critical_section_def) + +lemma peterson_rel_trans: + "peterson_rel ident x y \ peterson_rel ident y z \ + peterson_rel ident x z" + by (clarsimp simp: peterson_rel_def) + +lemma invs_set_label_Critical: + "invs s \ locked ident s \ ab_label s ident = Awaiting + \ invs (set_label ident Critical s)" + by (auto simp: invs_def invs_defs set_label_def locked_def) + +lemma acquire_lock_wp: + "\ \s0 s. invs s \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + acquire_lock ident + \ \\ \, + \ \rv s0 s. invs s \ ab_label s ident = Critical \" + apply (simp add: acquire_lock_def) + apply (rule validI_weaken_pre) + apply (wpsimp wp: Await_sync_twp)+ + apply (subst (asm) peterson_rel_imp_label, assumption+) + apply (drule(1) peterson_rel_imp_invs) + apply (drule(1) peterson_rel_trans) + apply (thin_tac "peterson_rel (other_ident ident) s'a x") + apply (frule peterson_rel_set_label) + apply (fastforce simp: set_label_def set_ab_def + locked_def invs_def invs_defs) + apply (drule peterson_rel_imp_invs) + apply (fastforce simp: set_label_def set_ab_def + locked_def invs_def invs_defs) + apply (clarsimp simp: invs_set_label_Critical) + apply (clarsimp simp: set_label_def set_ab_def) + done + +lemma acquire_lock_prefix_closed[simp]: + "prefix_closed (acquire_lock ident)" + by (auto intro!: prefix_closed_bind + simp: cs_closed acquire_lock_def) + +theorem peterson_proc_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + (\_ s. invs s \ ab_label s ident = Exited) + (\_ s. invs s \ ab_label s ident = Exited) + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + (abs_peterson_proc ident) + (peterson_proc ident)" + apply (simp add: abs_peterson_proc_def peterson_proc_def) + apply (rule prefix_refinement_weaken_pre) + apply (rule prefix_refinement_bind_sr) + apply (rule acquire_lock_refinement) + apply (rule prefix_refinement_bind_sr) + apply (rule critical_section_refinement) + apply (rule release_lock_refinement) + apply (wpsimp wp: validI_triv acquire_lock_wp + simp: bipred_conj_def)+ + done + +definition + peterson_rel2 :: "ident \ ('a, 'b) p_state \ ('a, 'b) p_state \ bool" +where + "peterson_rel2 ident s_prior s = ((* assume invs *) invs s_prior \ + (* If you're in the critical section, I won't change cs1_v *) + (critical (ab_label s_prior (other_ident ident)) + \ cs1_v s = cs1_v s_prior))" + +definition + peterson_rel3 :: "ident \ ('a, 'b) p_state \ ('a, 'b) p_state \ bool" +where + "peterson_rel3 ident s_prior s = ((* assume invs *) invs s_prior \ + (* invariants are preserved *) + (invs s + (* I won't adjust your variables *) + \ (ab_v s (other_ident ident) = ab_v s_prior (other_ident ident)) + \ (ab_label s (other_ident ident) = ab_label s_prior (other_ident ident)) + (* I will only ever give you priority *) + \ (t_v s_prior = other_ident ident \ t_v s = other_ident ident) + (* If you're in the critical section, I won't change cs2_v *) + \ (critical (ab_label s_prior (other_ident ident)) + \ cs2_v s = cs2_v s_prior)))" + +lemma peterson_rel_helpers: + "peterson_rel2 ident s0 s \ peterson_rel3 ident s0 s + \ peterson_rel ident s0 s" + by (clarsimp simp: peterson_rel_def peterson_rel2_def peterson_rel3_def) + +lemma peterson_rel_peterson_rel2: + "peterson_rel ident s0 s \ peterson_rel2 ident s0 s" + by (clarsimp simp: peterson_rel_def peterson_rel2_def) + +lemma peterson_sr_peterson_rel3: + "peterson_sr as0 cs0 \ peterson_sr as cs + \ peterson_rel ident as0 as \ peterson_rel3 ident cs0 cs" + apply (clarsimp simp: peterson_rel_def peterson_rel3_def invs_def + invs_defs peterson_sr_ab_label) + apply (clarsimp simp: peterson_sr_def) + done + +lemma peterson_proc_prefix_closed[simp]: + "prefix_closed (peterson_proc ident)" + by (auto intro!: prefix_closed_bind + simp: cs_closed peterson_proc_def acquire_lock_def release_lock_def) + +lemma peterson_proc_mutual_excl_helper: + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + peterson_proc ident + \ peterson_rel3 ident \, + \ \rv s0 s. peterson_rel3 ident s0 s \ invs s + \ ab_label s ident = Exited \" + apply (rule prefix_refinement_validI') + apply (rule peterson_proc_refinement) + apply (rule abs_peterson_proc_mutual_excl) + apply (clarsimp simp: peterson_sr_peterson_rel3 peterson_sr_ab_label) + apply (clarsimp simp: peterson_sr_peterson_rel3) + apply clarsimp + apply (rule_tac x=t0 in exI) + apply (rule_tac x="t \cs1_v := cs1_v t0\" in exI) + apply (clarsimp simp: peterson_rel_def peterson_sr_def) + apply clarsimp + apply (rule_tac x="t \cs1_v := cs1_v s0\" in exI) + apply (clarsimp simp: peterson_rel_def peterson_sr_def invs_def invs_defs) + apply clarsimp + done + +lemma peterson_proc_mutual_excl_helper': + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + peterson_proc ident + \ peterson_rel2 ident \, + \ \rv s0 s. peterson_rel2 ident s0 s \ invs s + \ ab_label s ident = Exited \" + apply (simp add: peterson_proc_def acquire_lock_def release_lock_def + critical_section_def) + apply (rule validI_weaken_pre) + apply (wp Await_sync_twp | simp add: split_def + | rule validI_strengthen_guar[OF _ allI[OF allI[OF peterson_rel_peterson_rel2]]])+ + apply (clarsimp simp: imp_conjL) + apply (strengthen peterson_rel_imp_assume_invs | simp)+ + apply (cases ident) + apply (safe, simp_all) + by ((clarsimp simp: peterson_rel_def peterson_rel2_def forall_ident_eq + set_label_def set_ab_def locked_def invs_defs cs_closed + | rule invs_def[THEN iffD2] conjI + | rev_drule invs_def[THEN iffD1])+) + +lemma peterson_proc_mutual_excl: + "\ \s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \, + \ peterson_rel (other_ident ident) \ + peterson_proc ident + \ peterson_rel ident \, + \ \rv s0 s. peterson_rel ident s0 s \ invs s + \ ab_label s ident = Exited \" + apply (rule validI_strengthen_guar, rule validI_strengthen_post, rule validI_guar_post_conj_lift) + apply (rule peterson_proc_mutual_excl_helper) + apply (rule peterson_proc_mutual_excl_helper') + apply (clarsimp simp: peterson_rel_helpers)+ + done + +definition "abs_peterson_proc_system \ + parallel (do repeat (abs_peterson_proc A); interference od) + (do repeat (abs_peterson_proc B); interference od)" + +lemma validI_repeat_interference: + "\P\, \R\ f \G\, \\_. P\ + \ \s0 s. P s0 s \ (\s'. R\<^sup>*\<^sup>* s s' \ Q () s' s') \ G s0 s + \ \P\, \R\ do repeat f; interference od \G\, \Q\" + apply (rule bind_twp) + apply simp + apply (rule interference_twp) + apply (rule validI_strengthen_post) + apply (rule repeat_validI, assumption) + apply simp + done + +lemma abs_peterson_proc_system_mutual_excl: + "\ \s0 s. s0 = s \ invs s \ ab_label s = (\_. Exited) \, + \ \s0 s. s0 = s \ + abs_peterson_proc_system + \ \s0 s. invs s0 \ invs s \, + \ \rv s0 s. invs s \" + apply (rule validI_weaken_pre, rule validI_strengthen_post) + apply (unfold abs_peterson_proc_system_def) + apply (rule rg_validI[where Qf="\_ _. invs" and Qg="\_ _. invs"]) + apply (rule validI_repeat_interference[OF abs_peterson_proc_mutual_excl]) + apply (clarsimp simp: peterson_rel_imp_invs) + apply (rule validI_repeat_interference[OF abs_peterson_proc_mutual_excl]) + apply (clarsimp simp: peterson_rel_imp_invs) + apply (simp add: reflp_ge_eq)+ + apply (clarsimp simp: peterson_rel_def)+ + done + +definition "peterson_proc_system \ + parallel (do repeat (peterson_proc A); interference od) + (do repeat (peterson_proc B); interference od)" + +lemma abs_peterson_proc_prefix_closed[simp]: + "prefix_closed (abs_peterson_proc ident)" + by (auto intro!: prefix_closed_bind + simp: cs_closed abs_peterson_proc_def acquire_lock_def release_lock_def) + +lemma peterson_repeat_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + (\s0 s. peterson_rel ident s0 s \ invs s \ ab_label s ident = Exited) + (\s0 s. peterson_rel ident s0 s \ invs s \ ab_label s ident = Exited) + (peterson_rel (other_ident ident)) (peterson_rel (other_ident ident)) + (do repeat (abs_peterson_proc ident); + interference + od) + (do repeat (peterson_proc ident); + interference + od)" + apply (rule prefix_refinement_weaken_pre) + apply (rule prefix_refinement_bind_sr) + apply (rule prefix_refinement_repeat[rotated]) + apply (rule abs_peterson_proc_mutual_excl[THEN validI_strengthen_guar]) + apply simp + apply (rule peterson_proc_mutual_excl[THEN validI_strengthen_guar, THEN validI_weaken_pre]) + apply simp+ + apply (rule peterson_proc_refinement[THEN prefix_refinement_weaken_pre]) + apply simp+ + apply (rule prefix_refinement_interference_peterson) + apply (wpsimp wp: validI_triv)+ + done + +theorem peterson_proc_system_refinement: + "prefix_refinement peterson_sr peterson_sr peterson_sr \\ + (\s0 s. s0 = s \ invs s \ ab_label s = (\_. Exited)) + (\t0 t. t0 = t \ invs t \ ab_label t = (\_. Exited)) + (\s0 s. s0 = s) (\t0 t. t0 = t) + abs_peterson_proc_system peterson_proc_system" + apply (unfold abs_peterson_proc_system_def peterson_proc_system_def) + apply (rule prefix_refinement_parallel') + apply (rule prefix_refinement_weaken_rely, rule prefix_refinement_weaken_pre) + apply (rule peterson_repeat_refinement) + apply simp + apply simp + apply (rule eq_refl, rule bipred_disj_op_eq, simp) + apply (rule eq_refl, rule bipred_disj_op_eq, simp) + apply (rule prefix_refinement_weaken_rely, rule prefix_refinement_weaken_pre) + apply (rule peterson_repeat_refinement) + apply simp + apply simp + apply (rule eq_refl, rule bipred_disj_op_eq, simp) + apply (rule eq_refl, rule bipred_disj_op_eq, simp) + apply (clarsimp intro!: par_tr_fin_bind par_tr_fin_interference) + apply (clarsimp intro!: par_tr_fin_bind par_tr_fin_interference) + apply (rule validI_weaken_pre, rule validI_weaken_rely) + apply (rule validI_repeat_interference; simp) + apply (rule peterson_proc_mutual_excl) + apply (simp+)[3] + apply (rule validI_weaken_pre, rule validI_weaken_rely) + apply (rule validI_repeat_interference; simp) + apply (rule peterson_proc_mutual_excl) + apply (simp+)[3] + apply (rule validI_weaken_pre, rule validI_weaken_rely) + apply (rule validI_repeat_interference; simp) + apply (rule abs_peterson_proc_mutual_excl) + apply (simp+)[3] + apply (rule validI_weaken_pre, rule validI_weaken_rely) + apply (rule validI_repeat_interference; simp) + apply (rule abs_peterson_proc_mutual_excl) + apply (simp+)[3] + done + +lemma peterson_proc_system_prefix_closed[simp]: + "prefix_closed (peterson_proc_system)" + by (auto intro!: prefix_closed_bind parallel_prefix_closed + simp: cs_closed peterson_proc_system_def) + +theorem peterson_proc_system_mutual_excl: + "\ \s0 s. s0 = s \ invs s \ ab_label s = (\_. Exited) \, + \ \s0 s. s0 = s \ + peterson_proc_system + \ \s0 s. invs s0 \ invs s \, + \ \rv s0 s. invs s \" + apply (rule prefix_refinement_validI') + apply (rule peterson_proc_system_refinement) + apply (rule abs_peterson_proc_system_mutual_excl) + apply clarsimp + apply (clarsimp simp: peterson_sr_invs_sym ) + apply (fastforce simp: peterson_rel_def peterson_sr_def) + apply clarsimp + apply (fastforce simp: peterson_sr_def) + done + +end +end diff --git a/lib/concurrency/examples/Plus2_Prefix.thy b/lib/concurrency/examples/Plus2_Prefix.thy new file mode 100644 index 000000000..0d3849c5c --- /dev/null +++ b/lib/concurrency/examples/Plus2_Prefix.thy @@ -0,0 +1,256 @@ +(* + * Copyright 2017, Data61, CSIRO + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + *) +theory Plus2_Prefix +imports + "../Prefix_Refinement" +begin + +section {* The plus2 example. *} + +text {* +This example presents an application of prefix refinement +to solve the plus2 verification problem. + +The function below can be proven to do two increments per +instance when grouped in parallel. But RG-reasoning doesn't +work well for this proof, since the state change (+1) performed +by the counterparts must be allowed by the rely, which must be +transitively closed, allowing any number of (+1) operations, +which is far too general. + +We address the issue with a ghost variable which records the number +of increments by each thread. We use prefix refinement to relate the +program with ghost variable to the initial program. +*} + +definition + "plus2 \ do env_steps; modify (op + (1 :: nat)); + interference; modify (op + 1); interference od" + +section {* The ghost-extended program. *} + +record + plus2_xstate = + mainv :: nat + threadv :: "nat \ nat" + +definition + point_update :: "'a \ ('b \ 'b) \ (('a \ 'b) \ ('a \ 'b))" +where + "point_update x fup f = f (x := fup (f x))" + +definition + "plus2_x tid \ do env_steps; + modify (mainv_update (op + 1) o threadv_update (point_update tid (op + 1))); + interference; + modify (mainv_update (op + 1) o threadv_update (point_update tid (op + 1))); + interference + od" + +section {* Verifying the extended @{term plus2}. *} +text {* The RG-reasoning needed to verify the @{term plus2_x} program. *} +definition + "plus2_inv tids s = (mainv s = sum (threadv s) tids)" + +definition + "plus2_rel tids fix_tids s0 s + = ((plus2_inv tids s0 \ plus2_inv tids s) \ (\tid \ fix_tids. threadv s tid = threadv s0 tid))" + +lemma plus2_rel_trans[simp]: + "rtranclp (plus2_rel tids ftids) = plus2_rel tids ftids" + apply (rule rtranclp_id2) + apply (simp add: plus2_rel_def) + apply (clarsimp simp: plus2_rel_def) + done + +lemma plus2_inv_Suc[simp]: + "tid \ tids \ finite tids + \ plus2_inv tids (mainv_update Suc (threadv_update (point_update tid Suc) s)) + = plus2_inv tids s" + apply (simp add: plus2_inv_def point_update_def) + apply (simp add: sum.If_cases[where h=f and g=f and P="op = tid" and A="tids" for f x, simplified]) + done + +theorem plus2_x_property: + "\\s0 s. plus2_inv tids s \ threadv s tid = 0 \ s = s0 \ tid \ tids \ finite tids\,\plus2_rel tids {tid}\ + plus2_x tid \plus2_rel tids (- {tid})\,\\_ _ s. plus2_inv tids s \ threadv s tid = 2\" + apply (simp add: plus2_x_def) + apply (rule validI_weaken_pre) + apply wp + apply clarsimp + apply (clarsimp simp: plus2_rel_def point_update_def) + done + +corollary plus2_x_parallel: + "\\s0 s. mainv s = 0 \ (\tid \ {1, 2}. threadv s tid = 0) \ s = s0\,\\a b. a = b\ + parallel (plus2_x 1) (plus2_x 2) \\s0 s. True\,\\_ s0 s. mainv s = 4\" + apply (rule validI_weaken_pre) + apply (rule validI_strengthen_post) + apply ((rule rg_validI plus2_x_property[where tids="{1, 2}"])+; simp add: plus2_rel_def le_fun_def) + apply (clarsimp simp: plus2_inv_def bipred_conj_def) + apply (clarsimp simp add: bipred_conj_def plus2_inv_def) + done + +section {* Mapping across prefix refinement. *} +text {* Proving prefix refinement of @{term plus2} and @{term plus2_x} and +deriving the final result. *} + +lemma env_stable: + "env_stable AR R (\s t. t = mainv s) (\s t. t = mainv s) \" + apply (simp add: env_stable_def rely_stable_def env_rely_stable_iosr_def) + apply (simp add: plus2_xstate.splits) + done + +abbreviation(input) + "p_refn rvr P Q AR R \ prefix_refinement (\s t. t = mainv s) (\s t. t = mainv s) + (\s t. t = mainv s) rvr P Q AR R" + +theorem pfx_refn_plus2_x: + "p_refn (\\) (op =) (\\) AR R (plus2_x tid) plus2" + apply (simp add: plus2_x_def plus2_def) + apply (rule prefix_refinement_weaken_pre) + apply (rule pfx_refn_bind prefix_refinement_interference + prefix_refinement_env_steps allI + pfx_refn_modifyT env_stable + | simp + | wp)+ + done + +lemma par_tr_fin_plus2_x: + "par_tr_fin_principle (plus2_x tid)" + by (simp add: plus2_x_def par_tr_fin_interference par_tr_fin_bind) + +lemma prefix_closed_plus2: + "prefix_closed plus2" + apply (simp add: plus2_def) + apply (rule validI_prefix_closed_T, rule validI_weaken_pre, wp) + apply simp + done + +theorem plus2_parallel: + "\\s0 s. s = 0 \ s = s0\,\\a b. a = b\ + parallel plus2 plus2 \\s0 s. True\,\\_ s0 s. s = 4\" + apply (rule_tac sr="\s t. t = mainv s" in prefix_refinement_validI) + apply (rule prefix_refinement_parallel_triv; + ((rule par_tr_fin_plus2_x prefix_closed_plus2)?)) + apply (rule pfx_refn_plus2_x[where tid=1]) + apply (rule pfx_refn_plus2_x[where tid=2]) + apply clarsimp + apply (rule validI_strengthen_post) + apply (rule plus2_x_parallel[simplified]) + apply clarsimp + apply (clarsimp simp: plus2_xstate.splits) + apply (strengthen exI[where x="f(1 := x, 2 := y)" for f x y]) + apply simp + apply clarsimp + apply (intro parallel_prefix_closed prefix_closed_plus2) + done + +section {* Generalising *} +text {* Just for fun, generalise to arbitrarily many +copies of the @{term plus2} program. *} + +lemma plus2_x_n_parallel_induct: + "n > 0 \ n \ N \ + \\s0 s. plus2_inv {..< N} s \ (\i < N. threadv s i = 0) \ s = s0\,\plus2_rel {..< N} {..< n}\ + fold parallel (map plus2_x [1 ..< n]) (plus2_x 0) \plus2_rel {..< N} ( - {..< n})\,\\_ _ s. + plus2_inv {..< N} s \ (\i < n. threadv s i = 2)\" + apply (induct n) + apply simp + apply (case_tac n) + apply (simp only: lessThan_Suc) + apply simp + apply (rule validI_weaken_pre, rule plus2_x_property) + apply clarsimp + apply (clarsimp split del: if_split) + apply (rule validI_weaken_pre, rule validI_strengthen_post, + rule rg_validI, rule plus2_x_property[where tids="{..< N}"], + assumption, (clarsimp simp: plus2_rel_def)+) + apply (auto dest: less_Suc_eq[THEN iffD1])[1] + apply (clarsimp simp: bipred_conj_def) + done + +theorem plus2_x_n_parallel: + "n > 0 \ + \\s0 s. mainv s = 0 \ (\i < n. threadv s i = 0) \ s = s0\,\plus2_rel {..< n} {..< n}\ + fold parallel (map plus2_x [1 ..< n]) (plus2_x 0) \\s0 s. True\,\\_ _ s. mainv s = (n * 2)\" + apply (rule validI_weaken_pre, rule validI_strengthen_post, + rule validI_strengthen_guar, erule plus2_x_n_parallel_induct) + apply simp + apply simp + apply (clarsimp simp: plus2_inv_def) + apply (clarsimp simp: plus2_inv_def) + done + +lemma par_tr_fin_principle_parallel: + "par_tr_fin_principle f \ par_tr_fin_principle g + \ par_tr_fin_principle (parallel f g)" + apply (subst par_tr_fin_principle_def, clarsimp simp: parallel_def3) + apply (drule(1) par_tr_fin_principleD)+ + apply (clarsimp simp: neq_Nil_conv) + done + +lemma fold_parallel_par_tr_fin_principle[where xs="rev xs" for xs, simplified]: + "\x \ insert x (set xs). par_tr_fin_principle x + \ par_tr_fin_principle (fold parallel (rev xs) x)" + by (induct xs, simp_all add: par_tr_fin_principle_parallel) + +lemma fold_parallel_prefix_closed[where xs="rev xs" for xs, simplified]: + "\x \ insert x (set xs). prefix_closed x + \ prefix_closed (fold parallel (rev xs) x)" + by (induct xs, simp_all add: parallel_prefix_closed) + +lemma bipred_disj_top_eq: + "(Rel Or (\_ _. True)) = (\_ _. True)" + "((\_ _. True) Or Rel) = (\_ _. True)" + by (auto simp add: bipred_disj_def) + +lemma fold_parallel_pfx_refn_induct: + "list_all2 (prefix_refinement sr sr sr (\_ _. True) P Q (\\) (\\)) xs ys + \ prefix_refinement sr sr sr (\_ _. True) P Q (\\) (\\) x y + \ \x \ set (x # xs). par_tr_fin_principle x + \ \y \ set (y # ys). prefix_closed y + \ prefix_refinement sr sr sr (\_ _. True) P Q (\\) (\\) + (fold parallel (rev xs) x) (fold parallel (rev ys) y)" + apply (induct rule: list_all2_induct; simp) + apply (rule prefix_refinement_parallel_triv[simplified bipred_disj_top_eq]; simp?) + apply (clarsimp simp: fold_parallel_par_tr_fin_principle + fold_parallel_prefix_closed)+ + done + +lemmas fold_parallel_pfx_refn + = fold_parallel_pfx_refn_induct[where xs="rev xs" and ys="rev ys" for xs ys, simplified] + +theorem plus2_n_parallel: + "n > 0 + \ \\s0 s. s = 0 \ s = s0\,\\a b. a = b\ + fold parallel (replicate (n - 1) plus2) plus2 \\s0 s. True\,\\_ s0 s. s = n * 2\" + apply (rule_tac sr="\s t. t = mainv s" in prefix_refinement_validI) + apply (rule prefix_refinement_weaken_rely, + rule_tac xs="map plus2_x [1 ..< n]" in fold_parallel_pfx_refn) + apply (clarsimp simp: list_all2_conv_all_nth) + apply (rule pfx_refn_plus2_x) + apply (rule pfx_refn_plus2_x[where tid=0]) + apply (simp add: par_tr_fin_plus2_x) + apply (simp add: prefix_closed_plus2) + apply (simp add: le_fun_def) + apply (simp add: le_fun_def) + apply simp + apply (rule validI_strengthen_post, rule plus2_x_n_parallel[simplified], simp) + apply clarsimp + apply (clarsimp simp: plus2_xstate.splits exI[where x="\_. 0"]) + apply clarsimp + apply (rule exI, strengthen refl) + apply (clarsimp simp: plus2_rel_def plus2_inv_def) + apply (rule fold_parallel_prefix_closed) + apply (simp add: prefix_closed_plus2) + done + +end