(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: BSD-2-Clause *) theory NonDetMonadVCG imports NonDetMonadLemmas WPSimp Strengthen begin declare K_def [simp] section "Satisfiability" text \ The dual to validity: an existential instead of a universal quantifier for the post condition. In refinement, it is often sufficient to know that there is one state that satisfies a condition. \ definition exs_valid :: "('a \ bool) \ ('a, 'b) nondet_monad \ ('b \ 'a \ bool) \ bool" ("\_\ _ \\_\") where "exs_valid P f Q \ (\s. P s \ (\(rv, s') \ fst (f s). Q rv s'))" text \The above for the exception monad\ definition ex_exs_validE :: "('a \ bool) \ ('a, 'e + 'b) nondet_monad \ ('b \ 'a \ bool) \ ('e \ 'a \ bool) \ bool" ("\_\ _ \\_\, \_\") where "ex_exs_validE P f Q E \ exs_valid P f (\rv. case rv of Inl e \ E e | Inr v \ Q v)" section "Lemmas" subsection \Determinism\ lemma det_set_iff: "det f \ (r \ fst (f s)) = (fst (f s) = {r})" apply (simp add: det_def) apply (rule iffI) apply (erule_tac x=s in allE) apply auto done lemma return_det [iff]: "det (return x)" by (simp add: det_def return_def) lemma put_det [iff]: "det (put s)" by (simp add: det_def put_def) lemma get_det [iff]: "det get" by (simp add: det_def get_def) lemma det_gets [iff]: "det (gets f)" by (auto simp add: gets_def det_def get_def return_def bind_def) lemma det_UN: "det f \ (\x \ fst (f s). g x) = (g (THE x. x \ fst (f s)))" unfolding det_def apply simp apply (drule spec [of _ s]) apply clarsimp done lemma bind_detI [simp, intro!]: "\ det f; \x. det (g x) \ \ det (f >>= g)" apply (simp add: bind_def det_def split_def) apply clarsimp apply (erule_tac x=s in allE) apply clarsimp apply (erule_tac x="a" in allE) apply (erule_tac x="b" in allE) apply clarsimp done lemma the_run_stateI: "fst (M s) = {s'} \ the_run_state M s = s'" by (simp add: the_run_state_def) lemma the_run_state_det: "\ s' \ fst (M s); det M \ \ the_run_state M s = s'" by (simp add: the_run_stateI det_set_iff) subsection "Lifting and Alternative Basic Definitions" lemma liftE_liftM: "liftE = liftM Inr" apply (rule ext) apply (simp add: liftE_def liftM_def) done lemma liftME_liftM: "liftME f = liftM (case_sum Inl (Inr \ f))" apply (rule ext) apply (simp add: liftME_def liftM_def bindE_def returnOk_def lift_def) apply (rule_tac f="bind x" in arg_cong) apply (rule ext) apply (case_tac xa) apply (simp_all add: lift_def throwError_def) done lemma liftE_bindE: "(liftE a) >>=E b = a >>= b" apply (simp add: liftE_def bindE_def lift_def bind_assoc) done lemma liftM_id[simp]: "liftM id = id" apply (rule ext) apply (simp add: liftM_def) done lemma liftM_bind: "(liftM t f >>= g) = (f >>= (\x. g (t x)))" by (simp add: liftM_def bind_assoc) lemma gets_bind_ign: "gets f >>= (\x. m) = m" apply (rule ext) apply (simp add: bind_def simpler_gets_def) done lemma get_bind_apply: "(get >>= f) x = f x x" by (simp add: get_def bind_def) lemma exec_gets: "(gets f >>= m) s = m (f s) s" by (simp add: simpler_gets_def bind_def) lemma exec_get: "(get >>= m) s = m s s" by (simp add: get_def bind_def) lemma bind_eqI: "\ f = f'; \x. g x = g' x \ \ f >>= g = f' >>= g'" apply (rule ext) apply (simp add: bind_def) apply (auto simp: split_def) done subsection "Simplification Rules for Lifted And/Or" lemma pred_andE[elim!]: "\ (A and B) x; \ A x; B x \ \ R \ \ R" by(simp add:pred_conj_def) lemma pred_andI[intro!]: "\ A x; B x \ \ (A and B) x" by(simp add:pred_conj_def) lemma pred_conj_app[simp]: "(P and Q) x = (P x \ Q x)" by(simp add:pred_conj_def) lemma bipred_andE[elim!]: "\ (A And B) x y; \ A x y; B x y \ \ R \ \ R" by(simp add:bipred_conj_def) lemma bipred_andI[intro!]: "\ A x y; B x y \ \ (A And B) x y" by (simp add:bipred_conj_def) lemma bipred_conj_app[simp]: "(P And Q) x = (P x and Q x)" by(simp add:pred_conj_def bipred_conj_def) lemma pred_disjE[elim!]: "\ (P or Q) x; P x \ R; Q x \ R \ \ R" by (fastforce simp: pred_disj_def) lemma pred_disjI1[intro]: "P x \ (P or Q) x" by (simp add: pred_disj_def) lemma pred_disjI2[intro]: "Q x \ (P or Q) x" by (simp add: pred_disj_def) lemma pred_disj_app[simp]: "(P or Q) x = (P x \ Q x)" by auto lemma bipred_disjI1[intro]: "P x y \ (P Or Q) x y" by (simp add: bipred_disj_def) lemma bipred_disjI2[intro]: "Q x y \ (P Or Q) x y" by (simp add: bipred_disj_def) lemma bipred_disj_app[simp]: "(P Or Q) x = (P x or Q x)" by(simp add:pred_disj_def bipred_disj_def) lemma pred_notnotD[simp]: "(not not P) = P" by(simp add:pred_neg_def) lemma pred_and_true[simp]: "(P and \) = P" by(simp add:pred_conj_def) lemma pred_and_true_var[simp]: "(\ and P) = P" by(simp add:pred_conj_def) lemma pred_and_false[simp]: "(P and \) = \" by(simp add:pred_conj_def) lemma pred_and_false_var[simp]: "(\ and P) = \" by(simp add:pred_conj_def) lemma pred_conj_assoc: "(P and Q and R) = (P and (Q and R))" unfolding pred_conj_def by simp subsection "Hoare Logic Rules" lemma validE_def2: "\P\ f \Q\,\R\ \ \s. P s \ (\(r,s') \ fst (f s). case r of Inr b \ Q b s' | Inl a \ R a s')" by (unfold valid_def validE_def) lemma seq': "\ \A\ f \B\; \x. P x \ \C\ g x \D\; \x s. B x s \ P x \ C s \ \ \A\ do x \ f; g x od \D\" apply (clarsimp simp: valid_def bind_def) apply fastforce done lemma seq: assumes f_valid: "\A\ f \B\" assumes g_valid: "\x. P x \ \C\ g x \D\" assumes bind: "\x s. B x s \ P x \ C s" shows "\A\ do x \ f; g x od \D\" apply (insert f_valid g_valid bind) apply (blast intro: seq') done lemma seq_ext': "\ \A\ f \B\; \x. \B x\ g x \C\ \ \ \A\ do x \ f; g x od \C\" by (fastforce simp: valid_def bind_def Let_def split_def) lemma seq_ext: assumes f_valid: "\A\ f \B\" assumes g_valid: "\x. \B x\ g x \C\" shows "\A\ do x \ f; g x od \C\" apply(insert f_valid g_valid) apply(blast intro: seq_ext') done lemma seqE': "\ \A\ f \B\,\E\; \x. \B x\ g x \C\,\E\ \ \ \A\ doE x \ f; g x odE \C\,\E\" apply(simp add:bindE_def lift_def bind_def Let_def split_def) apply(clarsimp simp:validE_def2) apply (fastforce simp add: throwError_def return_def lift_def split: sum.splits) done lemma seqE: assumes f_valid: "\A\ f \B\,\E\" assumes g_valid: "\x. \B x\ g x \C\,\E\" shows "\A\ doE x \ f; g x odE \C\,\E\" apply(insert f_valid g_valid) apply(blast intro: seqE') done lemma hoare_TrueI: "\P\ f \\_. \\" by (simp add: valid_def) lemma hoareE_TrueI: "\P\ f \\_. \\, \\r. \\" by (simp add: validE_def valid_def) lemma hoare_True_E_R [simp]: "\P\ f \\r s. True\, -" by (auto simp add: validE_R_def validE_def valid_def split: sum.splits) lemma hoare_post_conj [intro]: "\ \ P \ a \ Q \; \ P \ a \ R \ \ \ \ P \ a \ Q And R \" by (fastforce simp: valid_def split_def bipred_conj_def) lemma hoare_pre_disj [intro]: "\ \ P \ a \ R \; \ Q \ a \ R \ \ \ \ P or Q \ a \ R \" by (simp add:valid_def pred_disj_def) lemma hoare_conj: "\ \P\ f \Q\; \P'\ f \Q'\ \ \ \P and P'\ f \Q And Q'\" unfolding valid_def by auto lemma hoare_post_taut: "\ P \ a \ \\ \" by (simp add:valid_def) lemma wp_post_taut: "\\r. True\ f \\r s. True\" by (rule hoare_post_taut) lemma wp_post_tautE: "\\r. True\ f \\r s. True\,\\f s. True\" proof - have P: "\r. (case r of Inl a \ True | _ \ True) = True" by (case_tac r, simp_all) show ?thesis by (simp add: validE_def P wp_post_taut) qed lemma hoare_pre_cont [simp]: "\ \ \ a \ P \" by (simp add:valid_def) subsection \Strongest Postcondition Rules\ lemma get_sp: "\P\ get \\a s. s = a \ P s\" by(simp add:get_def valid_def) lemma put_sp: "\\\ put a \\_ s. s = a\" by(simp add:put_def valid_def) lemma return_sp: "\P\ return a \\b s. b = a \ P s\" by(simp add:return_def valid_def) lemma assert_sp: "\ P \ assert Q \ \r s. P s \ Q \" by (simp add: assert_def fail_def return_def valid_def) lemma hoare_gets_sp: "\P\ gets f \\rv s. rv = f s \ P s\" by (simp add: valid_def simpler_gets_def) lemma hoare_return_drop_var [iff]: "\ Q \ return x \ \r. Q \" by (simp add:valid_def return_def) lemma hoare_gets [intro]: "\ \s. P s \ Q (f s) s \ \ \ P \ gets f \ Q \" by (simp add:valid_def gets_def get_def bind_def return_def) lemma hoare_modifyE_var: "\ \s. P s \ Q (f s) \ \ \ P \ modify f \ \r s. Q s \" by(simp add: valid_def modify_def put_def get_def bind_def) lemma hoare_if: "\ P \ \ Q \ a \ R \; \ P \ \ Q \ b \ R \ \ \ \ Q \ if P then a else b \ R \" by (simp add:valid_def) lemma hoare_pre_subst: "\ A = B; \A\ a \C\ \ \ \B\ a \C\" by(clarsimp simp:valid_def split_def) lemma hoare_post_subst: "\ B = C; \A\ a \B\ \ \ \A\ a \C\" by(clarsimp simp:valid_def split_def) lemma hoare_pre_tautI: "\ \A and P\ a \B\; \A and not P\ a \B\ \ \ \A\ a \B\" by(fastforce simp:valid_def split_def pred_conj_def pred_neg_def) lemma hoare_pre_imp: "\ \s. P s \ Q s; \Q\ a \R\ \ \ \P\ a \R\" by (fastforce simp add:valid_def) lemma hoare_post_imp: "\ \r s. Q r s \ R r s; \P\ a \Q\ \ \ \P\ a \R\" by(fastforce simp:valid_def split_def) lemma hoare_post_impErr': "\ \P\ a \Q\,\E\; \r s. Q r s \ R r s; \e s. E e s \ F e s \ \ \P\ a \R\,\F\" apply (simp add: validE_def) apply (rule_tac Q="\r s. case r of Inl a \ E a s | Inr b \ Q b s" in hoare_post_imp) apply (case_tac r) apply simp_all done lemma hoare_post_impErr: "\ \P\ a \Q\,\E\; \r s. Q r s \ R r s; \e s. E e s \ F e s \ \ \P\ a \R\,\F\" apply (blast intro: hoare_post_impErr') done lemma hoare_validE_cases: "\ \ P \ f \ Q \, \ \_ _. True \; \ P \ f \ \_ _. True \, \ R \ \ \ \ P \ f \ Q \, \ R \" by (simp add: validE_def valid_def split: sum.splits) blast lemma hoare_post_imp_dc: "\\P\ a \\r. Q\; \s. Q s \ R s\ \ \P\ a \\r. R\,\\r. R\" by (simp add: validE_def valid_def split: sum.splits) blast lemma hoare_post_imp_dc2: "\\P\ a \\r. Q\; \s. Q s \ R s\ \ \P\ a \\r. R\,\\r s. True\" by (simp add: validE_def valid_def split: sum.splits) blast lemma hoare_post_imp_dc2E: "\\P\ a \\r. Q\; \s. Q s \ R s\ \ \P\ a \\r s. True\, \\r. R\" by (simp add: validE_def valid_def split: sum.splits) fast lemma hoare_post_imp_dc2E_actual: "\\P\ a \\r. R\\ \ \P\ a \\r s. True\, \\r. R\" by (simp add: validE_def valid_def split: sum.splits) fast lemma hoare_post_imp_dc2_actual: "\\P\ a \\r. R\\ \ \P\ a \\r. R\, \\r s. True\" by (simp add: validE_def valid_def split: sum.splits) fast lemma hoare_post_impE: "\ \r s. Q r s \ R r s; \P\ a \Q\ \ \ \P\ a \R\" by (fastforce simp:valid_def split_def) lemma hoare_conjD1: "\P\ f \\rv. Q rv and R rv\ \ \P\ f \\rv. Q rv\" unfolding valid_def by auto lemma hoare_conjD2: "\P\ f \\rv. Q rv and R rv\ \ \P\ f \\rv. R rv\" unfolding valid_def by auto lemma hoare_post_disjI1: "\P\ f \\rv. Q rv\ \ \P\ f \\rv. Q rv or R rv\" unfolding valid_def by auto lemma hoare_post_disjI2: "\P\ f \\rv. R rv\ \ \P\ f \\rv. Q rv or R rv\" unfolding valid_def by auto lemma hoare_weaken_pre: "\\Q\ a \R\; \s. P s \ Q s\ \ \P\ a \R\" apply (rule hoare_pre_imp) prefer 2 apply assumption apply blast done lemma hoare_strengthen_post: "\\P\ a \Q\; \r s. Q r s \ R r s\ \ \P\ a \R\" apply (rule hoare_post_imp) prefer 2 apply assumption apply blast done lemma use_valid: "\(r, s') \ fst (f s); \P\ f \Q\; P s \ \ Q r s'" apply (simp add: valid_def) apply blast done lemma use_validE_norm: "\ (Inr r', s') \ fst (B s); \ P \ B \ Q \,\ E \; P s \ \ Q r' s'" apply (clarsimp simp: validE_def valid_def) apply force done lemma use_validE_except: "\ (Inl r', s') \ fst (B s); \ P \ B \ Q \,\ E \; P s \ \ E r' s'" apply (clarsimp simp: validE_def valid_def) apply force done lemma in_inv_by_hoareD: "\ \P. \P\ f \\_. P\; (x,s') \ fst (f s) \ \ s' = s" by (auto simp add: valid_def) blast subsection "Satisfiability" lemma exs_hoare_post_imp: "\\r s. Q r s \ R r s; \P\ a \\Q\\ \ \P\ a \\R\" apply (simp add: exs_valid_def) apply safe apply (erule_tac x=s in allE, simp) apply blast done lemma use_exs_valid: "\\P\ f \\Q\; P s \ \ \(r, s') \ fst (f s). Q r s'" by (simp add: exs_valid_def) definition "exs_postcondition P f \ (\a b. \(rv, s)\ f a b. P rv s)" lemma exs_valid_is_triple: "exs_valid P f Q = triple_judgement P f (exs_postcondition Q (\s f. fst (f s)))" by (simp add: triple_judgement_def exs_postcondition_def exs_valid_def) lemmas [wp_trip] = exs_valid_is_triple lemma exs_valid_weaken_pre[wp_pre]: "\ \ P' \ f \\ Q \; \s. P s \ P' s \ \ \ P \ f \\ Q \" apply atomize apply (clarsimp simp: exs_valid_def) done lemma exs_valid_chain: "\ \ P \ f \\ Q \; \s. R s \ P s; \r s. Q r s \ S r s \ \ \ R \ f \\ S \" apply atomize apply (fastforce simp: exs_valid_def Bex_def) done lemma exs_valid_assume_pre: "\ \s. P s \ \ P \ f \\ Q \ \ \ \ P \ f \\ Q \" apply (fastforce simp: exs_valid_def) done lemma exs_valid_bind [wp_split]: "\ \x. \B x\ g x \\C\; \A\ f \\B\ \ \ \ A \ f >>= (\x. g x) \\ C \" apply atomize apply (clarsimp simp: exs_valid_def bind_def') apply blast done lemma exs_valid_return [wp]: "\ Q v \ return v \\ Q \" by (clarsimp simp: exs_valid_def return_def) lemma exs_valid_select [wp]: "\ \s. \r \ S. Q r s \ select S \\ Q \" by (clarsimp simp: exs_valid_def select_def) lemma exs_valid_get [wp]: "\ \s. Q s s \ get \\ Q \" by (clarsimp simp: exs_valid_def get_def) lemma exs_valid_gets [wp]: "\ \s. Q (f s) s \ gets f \\ Q \" by (clarsimp simp: gets_def) wp lemma exs_valid_put [wp]: "\ Q v \ put v \\ Q \" by (clarsimp simp: put_def exs_valid_def) lemma exs_valid_state_assert [wp]: "\ \s. Q () s \ G s \ state_assert G \\ Q \" by (clarsimp simp: state_assert_def exs_valid_def get_def assert_def bind_def' return_def) lemmas exs_valid_guard = exs_valid_state_assert lemma exs_valid_fail [wp]: "\ \_. False \ fail \\ Q \" by (clarsimp simp: fail_def exs_valid_def) lemma exs_valid_condition [wp]: "\ \ P \ L \\ Q \; \ P' \ R \\ Q \ \ \ \ \s. (C s \ P s) \ (\ C s \ P' s) \ condition C L R \\ Q \" by (clarsimp simp: condition_def exs_valid_def split: sum.splits) subsection MISC lemma hoare_return_simp: "\P\ return x \Q\ = (\s. P s \ Q x s)" by (simp add: valid_def return_def) lemma hoare_gen_asm: "(P \ \P'\ f \Q\) \ \P' and K P\ f \Q\" by (fastforce simp add: valid_def) lemma hoare_gen_asm_lk: "(P \ \P'\ f \Q\) \ \K P and P'\ f \Q\" by (fastforce simp add: valid_def) \ \Useful for forward reasoning, when P is known. The first version allows weakening the precondition.\ lemma hoare_gen_asm_spec': "(\s. P s \ S \ R s) \ (S \ \R\ f \Q\) \ \P\ f \Q\" by (fastforce simp: valid_def) lemma hoare_gen_asm_spec: "(\s. P s \ S) \ (S \ \P\ f \Q\) \ \P\ f \Q\" by (rule hoare_gen_asm_spec'[where S=S and R=P]) simp lemma hoare_conjI: "\ \P\ f \Q\; \P\ f \R\ \ \ \P\ f \\r s. Q r s \ R r s\" unfolding valid_def by blast lemma hoare_disjI1: "\ \P\ f \Q\ \ \ \P\ f \\r s. Q r s \ R r s \" unfolding valid_def by blast lemma hoare_disjI2: "\ \P\ f \R\ \ \ \P\ f \\r s. Q r s \ R r s \" unfolding valid_def by blast lemma hoare_assume_pre: "(\s. P s \ \P\ f \Q\) \ \P\ f \Q\" by (auto simp: valid_def) lemma hoare_returnOk_sp: "\P\ returnOk x \\r s. r = x \ P s\, \Q\" by (simp add: valid_def validE_def returnOk_def return_def) lemma hoare_assume_preE: "(\s. P s \ \P\ f \Q\,\R\) \ \P\ f \Q\,\R\" by (auto simp: valid_def validE_def) lemma hoare_allI: "(\x. \P\f\Q x\) \ \P\f\\r s. \x. Q x r s\" by (simp add: valid_def) blast lemma validE_allI: "(\x. \P\ f \\r s. Q x r s\,\E\) \ \P\ f \\r s. \x. Q x r s\,\E\" by (fastforce simp: valid_def validE_def split: sum.splits) lemma hoare_exI: "\P\ f \Q x\ \ \P\ f \\r s. \x. Q x r s\" by (simp add: valid_def) blast lemma hoare_impI: "(R \ \P\f\Q\) \ \P\f\\r s. R \ Q r s\" by (simp add: valid_def) blast lemma validE_impI: " \\E. \P\ f \\_ _. True\,\E\; (P' \ \P\ f \Q\,\E\)\ \ \P\ f \\r s. P' \ Q r s\, \E\" by (fastforce simp: validE_def valid_def split: sum.splits) lemma hoare_case_option_wp: "\ \P\ f None \Q\; \x. \P' x\ f (Some x) \Q' x\ \ \ \case_option P P' v\ f v \\rv. case v of None \ Q rv | Some x \ Q' x rv\" by (cases v) auto subsection "Reasoning directly about states" lemma in_throwError: "((v, s') \ fst (throwError e s)) = (v = Inl e \ s' = s)" by (simp add: throwError_def return_def) lemma in_returnOk: "((v', s') \ fst (returnOk v s)) = (v' = Inr v \ s' = s)" by (simp add: returnOk_def return_def) lemma in_bind: "((r,s') \ fst ((do x \ f; g x od) s)) = (\s'' x. (x, s'') \ fst (f s) \ (r, s') \ fst (g x s''))" apply (simp add: bind_def split_def) apply force done lemma in_bindE_R: "((Inr r,s') \ fst ((doE x \ f; g x odE) s)) = (\s'' x. (Inr x, s'') \ fst (f s) \ (Inr r, s') \ fst (g x s''))" apply (simp add: bindE_def lift_def split_def bind_def) apply (clarsimp simp: throwError_def return_def lift_def split: sum.splits) apply safe apply (case_tac a) apply fastforce apply fastforce apply force done lemma in_bindE_L: "((Inl r, s') \ fst ((doE x \ f; g x odE) s)) \ (\s'' x. (Inr x, s'') \ fst (f s) \ (Inl r, s') \ fst (g x s'')) \ ((Inl r, s') \ fst (f s))" apply (simp add: bindE_def lift_def bind_def) apply safe apply (simp add: return_def throwError_def lift_def split_def split: sum.splits if_split_asm) apply force done lemma in_liftE: "((v, s') \ fst (liftE f s)) = (\v'. v = Inr v' \ (v', s') \ fst (f s))" by (force simp add: liftE_def bind_def return_def split_def) lemma in_whenE: "((v, s') \ fst (whenE P f s)) = ((P \ (v, s') \ fst (f s)) \ (\P \ v = Inr () \ s' = s))" by (simp add: whenE_def in_returnOk) lemma inl_whenE: "((Inl x, s') \ fst (whenE P f s)) = (P \ (Inl x, s') \ fst (f s))" by (auto simp add: in_whenE) lemma inr_in_unlessE_throwError[termination_simp]: "(Inr (), s') \ fst (unlessE P (throwError E) s) = (P \ s'=s)" by (simp add: unlessE_def returnOk_def throwError_def return_def) lemma in_fail: "r \ fst (fail s) = False" by (simp add: fail_def) lemma in_return: "(r, s') \ fst (return v s) = (r = v \ s' = s)" by (simp add: return_def) lemma in_assert: "(r, s') \ fst (assert P s) = (P \ s' = s)" by (simp add: assert_def return_def fail_def) lemma in_assertE: "(r, s') \ fst (assertE P s) = (P \ r = Inr () \ s' = s)" by (simp add: assertE_def returnOk_def return_def fail_def) lemma in_assert_opt: "(r, s') \ fst (assert_opt v s) = (v = Some r \ s' = s)" by (auto simp: assert_opt_def in_fail in_return split: option.splits) lemma in_get: "(r, s') \ fst (get s) = (r = s \ s' = s)" by (simp add: get_def) lemma in_gets: "(r, s') \ fst (gets f s) = (r = f s \ s' = s)" by (simp add: simpler_gets_def) lemma in_put: "(r, s') \ fst (put x s) = (s' = x \ r = ())" by (simp add: put_def) lemma in_when: "(v, s') \ fst (when P f s) = ((P \ (v, s') \ fst (f s)) \ (\P \ v = () \ s' = s))" by (simp add: when_def in_return) lemma in_modify: "(v, s') \ fst (modify f s) = (s'=f s \ v = ())" by (simp add: modify_def bind_def get_def put_def) lemma gets_the_in_monad: "((v, s') \ fst (gets_the f s)) = (s' = s \ f s = Some v)" by (auto simp: gets_the_def in_bind in_gets in_assert_opt split: option.split) lemma in_alternative: "(r,s') \ fst ((f \ g) s) = ((r,s') \ fst (f s) \ (r,s') \ fst (g s))" by (simp add: alternative_def) lemmas in_monad = inl_whenE in_whenE in_liftE in_bind in_bindE_L in_bindE_R in_returnOk in_throwError in_fail in_assertE in_assert in_return in_assert_opt in_get in_gets in_put in_when unlessE_whenE unless_when in_modify gets_the_in_monad in_alternative subsection "Non-Failure" lemma no_failD: "\ no_fail P m; P s \ \ \(snd (m s))" by (simp add: no_fail_def) lemma non_fail_modify [wp,simp]: "no_fail \ (modify f)" by (simp add: no_fail_def modify_def get_def put_def bind_def) lemma non_fail_gets_simp[simp]: "no_fail P (gets f)" unfolding no_fail_def gets_def get_def return_def bind_def by simp lemma non_fail_gets: "no_fail \ (gets f)" by simp lemma non_fail_select [simp]: "no_fail \ (select S)" by (simp add: no_fail_def select_def) lemma no_fail_pre: "\ no_fail P f; \s. Q s \ P s\ \ no_fail Q f" by (simp add: no_fail_def) lemma no_fail_alt [wp]: "\ no_fail P f; no_fail Q g \ \ no_fail (P and Q) (f \ g)" by (simp add: no_fail_def alternative_def) lemma no_fail_return [simp, wp]: "no_fail \ (return x)" by (simp add: return_def no_fail_def) lemma no_fail_get [simp, wp]: "no_fail \ get" by (simp add: get_def no_fail_def) lemma no_fail_put [simp, wp]: "no_fail \ (put s)" by (simp add: put_def no_fail_def) lemma no_fail_when [wp]: "(P \ no_fail Q f) \ no_fail (if P then Q else \) (when P f)" by (simp add: when_def) lemma no_fail_unless [wp]: "(\P \ no_fail Q f) \ no_fail (if P then \ else Q) (unless P f)" by (simp add: unless_def when_def) lemma no_fail_fail [simp, wp]: "no_fail \ fail" by (simp add: fail_def no_fail_def) lemmas [wp] = non_fail_gets lemma no_fail_assert [simp, wp]: "no_fail (\_. P) (assert P)" by (simp add: assert_def) lemma no_fail_assert_opt [simp, wp]: "no_fail (\_. P \ None) (assert_opt P)" by (simp add: assert_opt_def split: option.splits) lemma no_fail_case_option [wp]: assumes f: "no_fail P f" assumes g: "\x. no_fail (Q x) (g x)" shows "no_fail (if x = None then P else Q (the x)) (case_option f g x)" by (clarsimp simp add: f g) lemma no_fail_if [wp]: "\ P \ no_fail Q f; \P \ no_fail R g \ \ no_fail (if P then Q else R) (if P then f else g)" by simp lemma no_fail_apply [wp]: "no_fail P (f (g x)) \ no_fail P (f $ g x)" by simp lemma no_fail_undefined [simp, wp]: "no_fail \ undefined" by (simp add: no_fail_def) lemma no_fail_returnOK [simp, wp]: "no_fail \ (returnOk x)" by (simp add: returnOk_def) lemma no_fail_bind [wp]: assumes f: "no_fail P f" assumes g: "\rv. no_fail (R rv) (g rv)" assumes v: "\Q\ f \R\" shows "no_fail (P and Q) (f >>= (\rv. g rv))" apply (clarsimp simp: no_fail_def bind_def) apply (rule conjI) prefer 2 apply (erule no_failD [OF f]) apply clarsimp apply (drule (1) use_valid [OF _ v]) apply (drule no_failD [OF g]) apply simp done text \Empty results implies non-failure\ lemma empty_fail_modify [simp, wp]: "empty_fail (modify f)" by (simp add: empty_fail_def simpler_modify_def) lemma empty_fail_gets [simp, wp]: "empty_fail (gets f)" by (simp add: empty_fail_def simpler_gets_def) lemma empty_failD: "\ empty_fail m; fst (m s) = {} \ \ snd (m s)" by (simp add: empty_fail_def) lemma empty_fail_select_f [simp]: assumes ef: "fst S = {} \ snd S" shows "empty_fail (select_f S)" by (fastforce simp add: empty_fail_def select_f_def intro: ef) lemma empty_fail_bind [simp]: "\ empty_fail a; \x. empty_fail (b x) \ \ empty_fail (a >>= b)" apply (simp add: bind_def empty_fail_def split_def) apply clarsimp apply (case_tac "fst (a s) = {}") apply blast apply (clarsimp simp: ex_in_conv [symmetric]) done lemma empty_fail_return [simp, wp]: "empty_fail (return x)" by (simp add: empty_fail_def return_def) lemma empty_fail_mapM [simp]: assumes m: "\x. empty_fail (m x)" shows "empty_fail (mapM m xs)" proof (induct xs) case Nil thus ?case by (simp add: mapM_def sequence_def) next case Cons have P: "\m x xs. mapM m (x # xs) = (do y \ m x; ys \ (mapM m xs); return (y # ys) od)" by (simp add: mapM_def sequence_def Let_def) from Cons show ?case by (simp add: P m) qed lemma empty_fail [simp]: "empty_fail fail" by (simp add: fail_def empty_fail_def) lemma empty_fail_assert_opt [simp]: "empty_fail (assert_opt x)" by (simp add: assert_opt_def split: option.splits) lemma empty_fail_mk_ef: "empty_fail (mk_ef o m)" by (simp add: empty_fail_def mk_ef_def) lemma empty_fail_gets_map[simp]: "empty_fail (gets_map f p)" unfolding gets_map_def by simp subsection "Failure" lemma fail_wp: "\\x. True\ fail \Q\" by (simp add: valid_def fail_def) lemma failE_wp: "\\x. True\ fail \Q\,\E\" by (simp add: validE_def fail_wp) lemma fail_update [iff]: "fail (f s) = fail s" by (simp add: fail_def) text \We can prove postconditions using hoare triples\ lemma post_by_hoare: "\ \P\ f \Q\; P s; (r, s') \ fst (f s) \ \ Q r s'" apply (simp add: valid_def) apply blast done text \Weakest Precondition Rules\ lemma hoare_vcg_prop: "\\s. P\ f \\rv s. P\" by (simp add: valid_def) lemma return_wp: "\P x\ return x \P\" by(simp add:valid_def return_def) lemma get_wp: "\\s. P s s\ get \P\" by(simp add:valid_def split_def get_def) lemma gets_wp: "\\s. P (f s) s\ gets f \P\" by(simp add:valid_def split_def gets_def return_def get_def bind_def) lemma modify_wp: "\\s. P () (f s)\ modify f \P\" by(simp add:valid_def split_def modify_def get_def put_def bind_def) lemma put_wp: "\\s. P () x\ put x \P\" by(simp add:valid_def put_def) lemma returnOk_wp: "\P x\ returnOk x \P\,\E\" by(simp add:validE_def2 returnOk_def return_def) lemma throwError_wp: "\E e\ throwError e \P\,\E\" by(simp add:validE_def2 throwError_def return_def) lemma returnOKE_R_wp : "\P x\ returnOk x \P\, -" by (simp add: validE_R_def validE_def valid_def returnOk_def return_def) lemma liftE_wp: "\P\ f \Q\ \ \P\ liftE f \Q\,\E\" by(clarsimp simp:valid_def validE_def2 liftE_def split_def Let_def bind_def return_def) lemma catch_wp: "\ \x. \E x\ handler x \Q\; \P\ f \Q\,\E\ \ \ \P\ catch f handler \Q\" apply (unfold catch_def valid_def validE_def return_def) apply (fastforce simp: bind_def split: sum.splits) done lemma handleE'_wp: "\ \x. \F x\ handler x \Q\,\E\; \P\ f \Q\,\F\ \ \ \P\ f handler \Q\,\E\" apply (unfold handleE'_def valid_def validE_def return_def) apply (fastforce simp: bind_def split: sum.splits) done lemma handleE_wp: assumes x: "\x. \F x\ handler x \Q\,\E\" assumes y: "\P\ f \Q\,\F\" shows "\P\ f handler \Q\,\E\" by (simp add: handleE_def handleE'_wp [OF x y]) lemma hoare_vcg_if_split: "\ P \ \Q\ f \S\; \P \ \R\ g \S\ \ \ \\s. (P \ Q s) \ (\P \ R s)\ if P then f else g \S\" by simp lemma hoare_vcg_if_splitE: "\ P \ \Q\ f \S\,\E\; \P \ \R\ g \S\,\E\ \ \ \\s. (P \ Q s) \ (\P \ R s)\ if P then f else g \S\,\E\" by simp lemma hoare_liftM_subst: "\P\ liftM f m \Q\ = \P\ m \Q \ f\" apply (simp add: liftM_def bind_def return_def split_def) apply (simp add: valid_def Ball_def) apply (rule_tac f=All in arg_cong) apply (rule ext) apply fastforce done lemma liftE_validE[simp]: "\P\ liftE f \Q\,\E\ = \P\ f \Q\" apply (simp add: liftE_liftM validE_def hoare_liftM_subst o_def) done lemma liftM_wp: "\P\ m \Q \ f\ \ \P\ liftM f m \Q\" by (simp add: hoare_liftM_subst) lemma hoare_liftME_subst: "\P\ liftME f m \Q\,\E\ = \P\ m \Q \ f\,\E\" apply (simp add: validE_def liftME_liftM hoare_liftM_subst o_def) apply (rule_tac f="valid P m" in arg_cong) apply (rule ext)+ apply (case_tac x, simp_all) done lemma liftME_wp: "\P\ m \Q \ f\,\E\ \ \P\ liftME f m \Q\,\E\" by (simp add: hoare_liftME_subst) (* FIXME: Move *) lemma o_const_simp[simp]: "(\x. C) \ f = (\x. C)" by (simp add: o_def) lemma hoare_vcg_split_case_option: "\ \x. x = None \ \P x\ f x \R x\; \x y. x = Some y \ \Q x y\ g x y \R x\ \ \ \\s. (x = None \ P x s) \ (\y. x = Some y \ Q x y s)\ case x of None \ f x | Some y \ g x y \R x\" apply(simp add:valid_def split_def) apply(case_tac x, simp_all) done lemma hoare_vcg_split_case_optionE: assumes none_case: "\x. x = None \ \P x\ f x \R x\,\E x\" assumes some_case: "\x y. x = Some y \ \Q x y\ g x y \R x\,\E x\" shows "\\s. (x = None \ P x s) \ (\y. x = Some y \ Q x y s)\ case x of None \ f x | Some y \ g x y \R x\,\E x\" apply(case_tac x, simp_all) apply(rule none_case, simp) apply(rule some_case, simp) done lemma hoare_vcg_split_case_sum: "\ \x a. x = Inl a \ \P x a\ f x a \R x\; \x b. x = Inr b \ \Q x b\ g x b \R x\ \ \ \\s. (\a. x = Inl a \ P x a s) \ (\b. x = Inr b \ Q x b s) \ case x of Inl a \ f x a | Inr b \ g x b \R x\" apply(simp add:valid_def split_def) apply(case_tac x, simp_all) done lemma hoare_vcg_split_case_sumE: assumes left_case: "\x a. x = Inl a \ \P x a\ f x a \R x\" assumes right_case: "\x b. x = Inr b \ \Q x b\ g x b \R x\" shows "\\s. (\a. x = Inl a \ P x a s) \ (\b. x = Inr b \ Q x b s) \ case x of Inl a \ f x a | Inr b \ g x b \R x\" apply(case_tac x, simp_all) apply(rule left_case, simp) apply(rule right_case, simp) done lemma hoare_vcg_precond_imp: "\ \Q\ f \R\; \s. P s \ Q s \ \ \P\ f \R\" by (fastforce simp add:valid_def) lemma hoare_vcg_precond_impE: "\ \Q\ f \R\,\E\; \s. P s \ Q s \ \ \P\ f \R\,\E\" by (fastforce simp add:validE_def2) lemma hoare_seq_ext: assumes g_valid: "\x. \B x\ g x \C\" assumes f_valid: "\A\ f \B\" shows "\A\ do x \ f; g x od \C\" apply(insert f_valid g_valid) apply(blast intro: seq_ext') done lemma hoare_vcg_seqE: assumes g_valid: "\x. \B x\ g x \C\,\E\" assumes f_valid: "\A\ f \B\,\E\" shows "\A\ doE x \ f; g x odE \C\,\E\" apply(insert f_valid g_valid) apply(blast intro: seqE') done lemma hoare_seq_ext_nobind: "\ \B\ g \C\; \A\ f \\r s. B s\ \ \ \A\ do f; g od \C\" apply (clarsimp simp: valid_def bind_def Let_def split_def) apply fastforce done lemma hoare_seq_ext_nobindE: "\ \B\ g \C\,\E\; \A\ f \\r s. B s\,\E\ \ \ \A\ doE f; g odE \C\,\E\" apply (clarsimp simp:validE_def) apply (simp add:bindE_def Let_def split_def bind_def lift_def) apply (fastforce simp add: valid_def throwError_def return_def lift_def split: sum.splits) done lemma hoare_chain: "\ \P\ f \Q\; \s. R s \ P s; \r s. Q r s \ S r s \ \ \R\ f \S\" by(fastforce simp add:valid_def split_def) lemma validE_weaken: "\ \P'\ A \Q'\,\E'\; \s. P s \ P' s; \r s. Q' r s \ Q r s; \r s. E' r s \ E r s \ \ \P\ A \Q\,\E\" by (fastforce simp: validE_def2 split: sum.splits) lemmas hoare_chainE = validE_weaken lemma hoare_vcg_handle_elseE: "\ \P\ f \Q\,\E\; \e. \E e\ g e \R\,\F\; \x. \Q x\ h x \R\,\F\ \ \ \P\ f g h \R\,\F\" apply (simp add: handle_elseE_def validE_def) apply (rule seq_ext) apply assumption apply (case_tac x, simp_all) done lemma alternative_valid: assumes x: "\P\ f \Q\" assumes y: "\P\ f' \Q\" shows "\P\ f \ f' \Q\" apply (simp add: valid_def alternative_def) apply safe apply (simp add: post_by_hoare [OF x]) apply (simp add: post_by_hoare [OF y]) done lemma alternative_wp: assumes x: "\P\ f \Q\" assumes y: "\P'\ f' \Q\" shows "\P and P'\ f \ f' \Q\" apply (rule alternative_valid) apply (rule hoare_pre_imp [OF _ x], simp) apply (rule hoare_pre_imp [OF _ y], simp) done lemma alternativeE_wp: assumes x: "\P\ f \Q\,\E\" and y: "\P'\ f' \Q\,\E\" shows "\P and P'\ f \ f' \Q\,\E\" apply (unfold validE_def) apply (wp add: x y alternative_wp | simp | fold validE_def)+ done lemma alternativeE_R_wp: "\ \P\ f \Q\,-; \P'\ f' \Q\,- \ \ \P and P'\ f \ f' \Q\,-" apply (simp add: validE_R_def) apply (rule alternativeE_wp) apply assumption+ done lemma alternative_R_wp: "\ \P\ f -,\Q\; \P'\ g -,\Q\ \ \ \P and P'\ f \ g -, \Q\" by (fastforce simp: alternative_def validE_E_def validE_def valid_def) lemma select_wp: "\\s. \x \ S. Q x s\ select S \Q\" by (simp add: select_def valid_def) lemma select_f_wp: "\\s. \x\fst S. Q x s\ select_f S \Q\" by (simp add: select_f_def valid_def) lemma state_select_wp [wp]: "\ \s. \t. (s, t) \ f \ P () t \ state_select f \ P \" apply (clarsimp simp: state_select_def) apply (clarsimp simp: valid_def) done lemma condition_wp [wp]: "\ \ Q \ A \ P \; \ R \ B \ P \ \ \ \ \s. if C s then Q s else R s \ condition C A B \ P \" apply (clarsimp simp: condition_def) apply (clarsimp simp: valid_def pred_conj_def pred_neg_def split_def) done lemma conditionE_wp [wp]: "\ \ P \ A \ Q \,\ R \; \ P' \ B \ Q \,\ R \ \ \ \ \s. if C s then P s else P' s \ condition C A B \Q\,\R\" apply (clarsimp simp: condition_def) apply (clarsimp simp: validE_def valid_def) done lemma state_assert_wp [wp]: "\ \s. f s \ P () s \ state_assert f \ P \" apply (clarsimp simp: state_assert_def get_def assert_def bind_def valid_def return_def fail_def) done text \The weakest precondition handler which works on conjunction\ lemma hoare_vcg_conj_lift: assumes x: "\P\ f \Q\" assumes y: "\P'\ f \Q'\" shows "\\s. P s \ P' s\ f \\rv s. Q rv s \ Q' rv s\" apply (subst bipred_conj_def[symmetric], rule hoare_post_conj) apply (rule hoare_pre_imp [OF _ x], simp) apply (rule hoare_pre_imp [OF _ y], simp) done lemma hoare_vcg_conj_liftE1: "\ \P\ f \Q\,-; \P'\ f \Q'\,\E\ \ \ \P and P'\ f \\r s. Q r s \ Q' r s\,\E\" unfolding valid_def validE_R_def validE_def apply (clarsimp simp: split_def split: sum.splits) apply (erule allE, erule (1) impE) apply (erule allE, erule (1) impE) apply (drule (1) bspec) apply (drule (1) bspec) apply clarsimp done lemma hoare_vcg_disj_lift: assumes x: "\P\ f \Q\" assumes y: "\P'\ f \Q'\" shows "\\s. P s \ P' s\ f \\rv s. Q rv s \ Q' rv s\" apply (simp add: valid_def) apply safe apply (erule(1) post_by_hoare [OF x]) apply (erule notE) apply (erule(1) post_by_hoare [OF y]) done lemma hoare_vcg_const_Ball_lift: "\ \x. x \ S \ \P x\ f \Q x\ \ \ \\s. \x\S. P x s\ f \\rv s. \x\S. Q x rv s\" by (fastforce simp: valid_def) lemma hoare_vcg_const_Ball_lift_R: "\ \x. x \ S \ \P x\ f \Q x\,- \ \ \\s. \x \ S. P x s\ f \\rv s. \x \ S. Q x rv s\,-" apply (simp add: validE_R_def validE_def) apply (rule hoare_strengthen_post) apply (erule hoare_vcg_const_Ball_lift) apply (simp split: sum.splits) done lemma hoare_vcg_all_lift: "\ \x. \P x\ f \Q x\ \ \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\" by (fastforce simp: valid_def) lemma hoare_vcg_all_lift_R: "(\x. \P x\ f \Q x\, -) \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\, -" by (rule hoare_vcg_const_Ball_lift_R[where S=UNIV, simplified]) lemma hoare_vcg_imp_lift: "\ \P'\ f \\rv s. \ P rv s\; \Q'\ f \Q\ \ \ \\s. P' s \ Q' s\ f \\rv s. P rv s \ Q rv s\" apply (simp only: imp_conv_disj) apply (erule(1) hoare_vcg_disj_lift) done lemma hoare_vcg_imp_lift': "\ \P'\ f \\rv s. \ P rv s\; \Q'\ f \Q\ \ \ \\s. \ P' s \ Q' s\ f \\rv s. P rv s \ Q rv s\" apply (simp only: imp_conv_disj) apply simp apply (erule (1) hoare_vcg_imp_lift) done lemma hoare_vcg_imp_conj_lift[wp_comb]: "\P\ f \\rv s. Q rv s \ Q' rv s\ \ \P'\ f \\rv s. (Q rv s \ Q'' rv s) \ Q''' rv s\ \ \P and P'\ f \\rv s. (Q rv s \ Q' rv s \ Q'' rv s) \ Q''' rv s\" by (auto simp: valid_def) lemmas hoare_vcg_imp_conj_lift'[wp_unsafe] = hoare_vcg_imp_conj_lift[where Q'''="\\", simplified] lemma hoare_absorb_imp: "\ P \ f \\rv s. Q rv s \ R rv s \ \ \ P \ f \\rv s. Q rv s \ R rv s \" by (erule hoare_post_imp[rotated], blast) lemma hoare_weaken_imp: "\ \rv s. Q rv s \ Q' rv s ; \P\ f \\rv s. Q' rv s \ R rv s\ \ \ \P\ f \\rv s. Q rv s \ R rv s\" by (clarsimp simp: NonDetMonad.valid_def split_def) lemma hoare_vcg_const_imp_lift: "\ P \ \Q\ m \R\ \ \ \\s. P \ Q s\ m \\rv s. P \ R rv s\" by (cases P, simp_all add: hoare_vcg_prop) lemma hoare_vcg_const_imp_lift_R: "(P \ \Q\ m \R\,-) \ \\s. P \ Q s\ m \\rv s. P \ R rv s\,-" by (fastforce simp: validE_R_def validE_def valid_def split_def split: sum.splits) lemma hoare_weak_lift_imp: "\P'\ f \Q\ \ \\s. P \ P' s\ f \\rv s. P \ Q rv s\" by (auto simp add: valid_def split_def) lemma hoare_vcg_weaken_imp: "\ \rv s. Q rv s \ Q' rv s ; \ P \ f \\rv s. Q' rv s \ R rv s\ \ \ \ P \ f \\rv s. Q rv s \ R rv s\" by (clarsimp simp: valid_def split_def) lemma hoare_vcg_ex_lift: "\ \x. \P x\ f \Q x\ \ \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\" by (clarsimp simp: valid_def, blast) lemma hoare_vcg_ex_lift_R1: "(\x. \P x\ f \Q\, -) \ \\s. \x. P x s\ f \Q\, -" by (fastforce simp: valid_def validE_R_def validE_def split: sum.splits) lemma hoare_liftP_ext: assumes "\P x. m \\s. P (f s x)\" shows "m \\s. P (f s)\" unfolding valid_def apply clarsimp apply (erule rsubst[where P=P]) apply (rule ext) apply (drule use_valid, rule assms, rule refl) apply simp done (* for instantiations *) lemma hoare_triv: "\P\f\Q\ \ \P\f\Q\" . lemma hoare_trivE: "\P\ f \Q\,\E\ \ \P\ f \Q\,\E\" . lemma hoare_trivE_R: "\P\ f \Q\,- \ \P\ f \Q\,-" . lemma hoare_trivR_R: "\P\ f -,\E\ \ \P\ f -,\E\" . lemma hoare_weaken_preE_E: "\ \P'\ f -,\Q\; \s. P s \ P' s \ \ \P\ f -,\Q\" by (fastforce simp add: validE_E_def validE_def valid_def) lemma hoare_vcg_E_conj: "\ \P\ f -,\E\; \P'\ f \Q'\,\E'\ \ \ \\s. P s \ P' s\ f \Q'\, \\rv s. E rv s \ E' rv s\" apply (unfold validE_def validE_E_def) apply (rule hoare_post_imp [OF _ hoare_vcg_conj_lift], simp_all) apply (case_tac r, simp_all) done lemma hoare_vcg_E_elim: "\ \P\ f -,\E\; \P'\ f \Q\,- \ \ \\s. P s \ P' s\ f \Q\,\E\" by (rule hoare_post_impErr [OF hoare_vcg_E_conj], (simp add: validE_R_def)+) lemma hoare_vcg_R_conj: "\ \P\ f \Q\,-; \P'\ f \Q'\,- \ \ \\s. P s \ P' s\ f \\rv s. Q rv s \ Q' rv s\,-" apply (unfold validE_R_def validE_def) apply (rule hoare_post_imp [OF _ hoare_vcg_conj_lift], simp_all) apply (case_tac r, simp_all) done lemma valid_validE: "\P\ f \\rv. Q\ \ \P\ f \\rv. Q\,\\rv. Q\" apply (simp add: validE_def) done lemma valid_validE2: "\ \P\ f \\_. Q'\; \s. Q' s \ Q s; \s. Q' s \ E s \ \ \P\ f \\_. Q\,\\_. E\" unfolding valid_def validE_def by (clarsimp split: sum.splits) blast lemma validE_valid: "\P\ f \\rv. Q\,\\rv. Q\ \ \P\ f \\rv. Q\" apply (unfold validE_def) apply (rule hoare_post_imp) defer apply assumption apply (case_tac r, simp_all) done lemma hoare_lift_Pf_E_R: assumes P: "\x. \P x\ m \\_. P x\, -" assumes f: "\P. \\s. P (f s)\ m \\_ s. P (f s)\, -" shows "\\s. P (f s) s\ m \\_ s. P (f s) s\, -" using P f apply (clarsimp simp: validE_R_def validE_def valid_def) apply (rename_tac r s', case_tac r; simp) apply fastforce done lemma hoare_lift_Pf_E_E: assumes P: "\x. \P x\ m -, \\_. P x\" assumes f: "\P. \\s. P (f s)\ m -, \\_ s. P (f s)\" shows "\\s. P (f s) s\ m -, \\_ s. P (f s) s\" using P f apply (clarsimp simp: validE_E_def validE_def valid_def) apply (rename_tac r s', case_tac r; simp) apply fastforce done lemma hoare_vcg_const_Ball_lift_E_E: "\ \x. x \ S \ \P x\ f -,\Q x\ \ \ \\s. \x \ S. P x s\ f -,\\rv s. \x \ S. Q x rv s\" apply (simp add: validE_E_def validE_def) apply (rule hoare_strengthen_post) apply (erule hoare_vcg_const_Ball_lift) apply (simp split: sum.splits) done lemma hoare_vcg_all_liftE_E: "(\x. \P x\ f -, \Q x\) \ \\s. \x. P x s\ f -,\\rv s. \x. Q x rv s\" by (rule hoare_vcg_const_Ball_lift_E_E[where S=UNIV, simplified]) lemma hoare_vcg_imp_liftE_E: "\\P'\ f -, \\rv s. \ P rv s\; \Q'\ f -, \Q\\ \ \\s. \ P' s \ Q' s\ f -, \\rv s. P rv s \ Q rv s\" by (auto simp add: valid_def validE_E_def validE_def split_def split: sum.splits) lemma hoare_vcg_ex_liftE: "\ \x. \P x\ f \Q x\,\E\ \ \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\,\E\" by (fastforce simp: validE_def valid_def split: sum.splits) lemma hoare_vcg_ex_liftE_E: "\ \x. \P x\ f -,\E x\ \ \ \\s. \x. P x s\ f -,\\rv s. \x. E x rv s\" by (fastforce simp: validE_E_def validE_def valid_def split: sum.splits) lemma valid_validE_R: "\P\ f \\rv. Q\ \ \P\ f \\rv. Q\,-" by (simp add: validE_R_def hoare_post_impErr [OF valid_validE]) lemma valid_validE_E: "\P\ f \\rv. Q\ \ \P\ f -,\\rv. Q\" by (simp add: validE_E_def hoare_post_impErr [OF valid_validE]) lemma validE_validE_R: "\P\ f \Q\,\\\\ \ \P\ f \Q\,-" by (simp add: validE_R_def) lemma validE_R_validE: "\P\ f \Q\,- \ \P\ f \Q\,\\\\" by (simp add: validE_R_def) lemma validE_validE_E: "\P\ f \\\\,\E\ \ \P\ f -,\E\" by (simp add: validE_E_def) lemma validE_E_validE: "\P\ f -,\E\ \ \P\ f \\\\,\E\" by (simp add: validE_E_def) lemma hoare_post_imp_R: "\ \P\ f \Q'\,-; \r s. Q' r s \ Q r s \ \ \P\ f \Q\,-" apply (unfold validE_R_def) apply (erule hoare_post_impErr, simp+) done lemma hoare_post_imp_E: "\ \P\ f -,\Q'\; \r s. Q' r s \ Q r s \ \ \P\ f -,\Q\" apply (unfold validE_E_def) apply (erule hoare_post_impErr, simp+) done lemma hoare_post_comb_imp_conj: "\ \P'\ f \Q\; \P\ f \Q'\; \s. P s \ P' s \ \ \P\ f \\rv s. Q rv s \ Q' rv s\" apply (rule hoare_pre_imp) defer apply (rule hoare_vcg_conj_lift) apply assumption+ apply simp done lemma hoare_vcg_precond_impE_R: "\ \P'\ f \Q\,-; \s. P s \ P' s \ \ \P\ f \Q\,-" by (unfold validE_R_def, rule hoare_vcg_precond_impE, simp+) lemma valid_is_triple: "valid P f Q = triple_judgement P f (postcondition Q (\s f. fst (f s)))" by (simp add: triple_judgement_def valid_def postcondition_def) lemma validE_is_triple: "validE P f Q E = triple_judgement P f (postconditions (postcondition Q (\s f. {(rv, s'). (Inr rv, s') \ fst (f s)})) (postcondition E (\s f. {(rv, s'). (Inl rv, s') \ fst (f s)})))" apply (simp add: validE_def triple_judgement_def valid_def postcondition_def postconditions_def split_def split: sum.split) apply fastforce done lemma validE_R_is_triple: "validE_R P f Q = triple_judgement P f (postcondition Q (\s f. {(rv, s'). (Inr rv, s') \ fst (f s)}))" by (simp add: validE_R_def validE_is_triple postconditions_def postcondition_def) lemma validE_E_is_triple: "validE_E P f E = triple_judgement P f (postcondition E (\s f. {(rv, s'). (Inl rv, s') \ fst (f s)}))" by (simp add: validE_E_def validE_is_triple postconditions_def postcondition_def) lemmas hoare_wp_combs = hoare_vcg_conj_lift lemmas hoare_wp_combsE = validE_validE_R hoare_vcg_R_conj hoare_vcg_E_elim hoare_vcg_E_conj lemmas hoare_wp_state_combsE = valid_validE_R hoare_vcg_R_conj[OF valid_validE_R] hoare_vcg_E_elim[OF valid_validE_E] hoare_vcg_E_conj[OF valid_validE_E] lemmas hoare_classic_wp_combs = hoare_post_comb_imp_conj hoare_vcg_precond_imp hoare_wp_combs lemmas hoare_classic_wp_combsE = hoare_vcg_precond_impE hoare_vcg_precond_impE_R hoare_wp_combsE lemmas hoare_classic_wp_state_combsE = hoare_vcg_precond_impE[OF valid_validE] hoare_vcg_precond_impE_R[OF valid_validE_R] hoare_wp_state_combsE lemmas all_classic_wp_combs = hoare_classic_wp_state_combsE hoare_classic_wp_combsE hoare_classic_wp_combs lemmas hoare_wp_splits [wp_split] = hoare_seq_ext hoare_vcg_seqE handleE'_wp handleE_wp validE_validE_R [OF hoare_vcg_seqE [OF validE_R_validE]] validE_validE_R [OF handleE'_wp [OF validE_R_validE]] validE_validE_R [OF handleE_wp [OF validE_R_validE]] catch_wp hoare_vcg_if_split hoare_vcg_if_splitE validE_validE_R [OF hoare_vcg_if_splitE [OF validE_R_validE validE_R_validE]] liftM_wp liftME_wp validE_validE_R [OF liftME_wp [OF validE_R_validE]] validE_valid lemmas [wp_comb] = hoare_wp_state_combsE hoare_wp_combsE hoare_wp_combs lemmas [wp] = hoare_vcg_prop wp_post_taut return_wp put_wp get_wp gets_wp modify_wp returnOk_wp throwError_wp fail_wp failE_wp liftE_wp select_f_wp lemmas [wp_trip] = valid_is_triple validE_is_triple validE_E_is_triple validE_R_is_triple lemmas validE_E_combs[wp_comb] = hoare_vcg_E_conj[where Q'="\\", folded validE_E_def] valid_validE_E hoare_vcg_E_conj[where Q'="\\", folded validE_E_def, OF valid_validE_E] text \Simplifications on conjunction\ lemma hoare_post_eq: "\ Q = Q'; \P\ f \Q'\ \ \ \P\ f \Q\" by simp lemma hoare_post_eqE1: "\ Q = Q'; \P\ f \Q'\,\E\ \ \ \P\ f \Q\,\E\" by simp lemma hoare_post_eqE2: "\ E = E'; \P\ f \Q\,\E'\ \ \ \P\ f \Q\,\E\" by simp lemma hoare_post_eqE_R: "\ Q = Q'; \P\ f \Q'\,- \ \ \P\ f \Q\,-" by simp lemma pred_conj_apply_elim: "(\r. Q r and Q' r) = (\r s. Q r s \ Q' r s)" by (simp add: pred_conj_def) lemma pred_conj_conj_elim: "(\r s. (Q r and Q' r) s \ Q'' r s) = (\r s. Q r s \ Q' r s \ Q'' r s)" by simp lemma conj_assoc_apply: "(\r s. (Q r s \ Q' r s) \ Q'' r s) = (\r s. Q r s \ Q' r s \ Q'' r s)" by simp lemma all_elim: "(\rv s. \x. P rv s) = P" by simp lemma all_conj_elim: "(\rv s. (\x. P rv s) \ Q rv s) = (\rv s. P rv s \ Q rv s)" by simp lemmas vcg_rhs_simps = pred_conj_apply_elim pred_conj_conj_elim conj_assoc_apply all_elim all_conj_elim lemma if_apply_reduct: "\P\ If P' (f x) (g x) \Q\ \ \P\ If P' f g x \Q\" by (cases P', simp_all) lemma if_apply_reductE: "\P\ If P' (f x) (g x) \Q\,\E\ \ \P\ If P' f g x \Q\,\E\" by (cases P', simp_all) lemma if_apply_reductE_R: "\P\ If P' (f x) (g x) \Q\,- \ \P\ If P' f g x \Q\,-" by (cases P', simp_all) lemmas hoare_wp_simps [wp_split] = vcg_rhs_simps [THEN hoare_post_eq] vcg_rhs_simps [THEN hoare_post_eqE1] vcg_rhs_simps [THEN hoare_post_eqE2] vcg_rhs_simps [THEN hoare_post_eqE_R] if_apply_reduct if_apply_reductE if_apply_reductE_R TrueI schematic_goal if_apply_test: "\?Q\ (if A then returnOk else K fail) x \P\,\E\" by wpsimp lemma hoare_elim_pred_conj: "\P\ f \\r s. Q r s \ Q' r s\ \ \P\ f \\r. Q r and Q' r\" by (unfold pred_conj_def) lemma hoare_elim_pred_conjE1: "\P\ f \\r s. Q r s \ Q' r s\,\E\ \ \P\ f \\r. Q r and Q' r\,\E\" by (unfold pred_conj_def) lemma hoare_elim_pred_conjE2: "\P\ f \Q\, \\x s. E x s \ E' x s\ \ \P\ f \Q\,\\x. E x and E' x\" by (unfold pred_conj_def) lemma hoare_elim_pred_conjE_R: "\P\ f \\r s. Q r s \ Q' r s\,- \ \P\ f \\r. Q r and Q' r\,-" by (unfold pred_conj_def) lemmas hoare_wp_pred_conj_elims = hoare_elim_pred_conj hoare_elim_pred_conjE1 hoare_elim_pred_conjE2 hoare_elim_pred_conjE_R lemmas hoare_weaken_preE = hoare_vcg_precond_impE lemmas hoare_pre [wp_pre] = hoare_weaken_pre hoare_weaken_preE hoare_vcg_precond_impE_R hoare_weaken_preE_E declare no_fail_pre [wp_pre] bundle no_pre = hoare_pre [wp_pre del] no_fail_pre [wp_pre del] bundle classic_wp_pre = hoare_pre [wp_pre del] no_fail_pre [wp_pre del] all_classic_wp_combs[wp_comb del] all_classic_wp_combs[wp_comb] text \Miscellaneous lemmas on hoare triples\ lemma hoare_vcg_mp: assumes a: "\P\ f \Q\" assumes b: "\P\ f \\r s. Q r s \ Q' r s\" shows "\P\ f \Q'\" using assms by (auto simp: valid_def split_def) (* note about this precond stuff: rules get a chance to bind directly before any of their combined forms. As a result, these precondition implication rules are only used when needed. *) lemma hoare_add_post: assumes r: "\P'\ f \Q'\" assumes impP: "\s. P s \ P' s" assumes impQ: "\P\ f \\rv s. Q' rv s \ Q rv s\" shows "\P\ f \Q\" apply (rule hoare_chain) apply (rule hoare_vcg_conj_lift) apply (rule r) apply (rule impQ) apply simp apply (erule impP) apply simp done lemma hoare_gen_asmE: "(P \ \P'\ f \Q\,-) \ \P' and K P\ f \Q\, -" by (simp add: validE_R_def validE_def valid_def) blast lemma hoare_list_case: assumes P1: "\P1\ f f1 \Q\" assumes P2: "\y ys. xs = y#ys \ \P2 y ys\ f (f2 y ys) \Q\" shows "\case xs of [] \ P1 | y#ys \ P2 y ys\ f (case xs of [] \ f1 | y#ys \ f2 y ys) \Q\" apply (cases xs; simp) apply (rule P1) apply (rule P2) apply simp done lemma hoare_when_wp [wp_split]: "\ P \ \Q\ f \R\ \ \ \if P then Q else R ()\ when P f \R\" by (clarsimp simp: when_def valid_def return_def) lemma hoare_unless_wp[wp_split]: "(\P \ \Q\ f \R\) \ \if P then R () else Q\ unless P f \R\" unfolding unless_def by wp auto lemma hoare_whenE_wp: "(P \ \Q\ f \R\, \E\) \ \if P then Q else R ()\ whenE P f \R\, \E\" unfolding whenE_def by clarsimp wp lemmas hoare_whenE_wps[wp_split] = hoare_whenE_wp hoare_whenE_wp[THEN validE_validE_R] hoare_whenE_wp[THEN validE_validE_E] lemma hoare_unlessE_wp: "(\ P \ \Q\ f \R\, \E\) \ \if P then R () else Q\ unlessE P f \R\, \E\" unfolding unlessE_def by wp auto lemmas hoare_unlessE_wps[wp_split] = hoare_unlessE_wp hoare_unlessE_wp[THEN validE_validE_R] hoare_unlessE_wp[THEN validE_validE_E] lemma hoare_use_eq: assumes x: "\P. \\s. P (f s)\ m \\rv s. P (f s)\" assumes y: "\f. \\s. P f s\ m \\rv s. Q f s\" shows "\\s. P (f s) s\ m \\rv s. Q (f s :: 'c :: type) s \" apply (rule_tac Q="\rv s. \f'. f' = f s \ Q f' s" in hoare_post_imp) apply simp apply (wpsimp wp: hoare_vcg_ex_lift x y) done lemma hoare_return_sp: "\P\ return x \\r. P and K (r = x)\" by (simp add: valid_def return_def) lemma hoare_fail_any [simp]: "\P\ fail \Q\" by wp lemma hoare_failE [simp]: "\P\ fail \Q\,\E\" by wp lemma hoare_FalseE [simp]: "\\s. False\ f \Q\,\E\" by (simp add: valid_def validE_def) lemma hoare_K_bind [wp_split]: "\P\ f \Q\ \ \P\ K_bind f x \Q\" by simp lemma validE_K_bind [wp_split]: "\ P \ x \ Q \, \ E \ \ \ P \ K_bind x f \ Q \, \ E \" by simp text \Setting up the precondition case splitter.\ lemma wpc_helper_valid: "\Q\ g \S\ \ wpc_helper (P, P') (Q, Q') \P\ g \S\" by (clarsimp simp: wpc_helper_def elim!: hoare_pre) lemma wpc_helper_validE: "\Q\ f \R\,\E\ \ wpc_helper (P, P') (Q, Q') \P\ f \R\,\E\" by (clarsimp simp: wpc_helper_def elim!: hoare_pre) lemma wpc_helper_validE_R: "\Q\ f \R\,- \ wpc_helper (P, P') (Q, Q') \P\ f \R\,-" by (clarsimp simp: wpc_helper_def elim!: hoare_pre) lemma wpc_helper_validR_R: "\Q\ f -,\E\ \ wpc_helper (P, P') (Q, Q') \P\ f -,\E\" by (clarsimp simp: wpc_helper_def elim!: hoare_pre) lemma wpc_helper_no_fail_final: "no_fail Q f \ wpc_helper (P, P') (Q, Q') (no_fail P f)" by (clarsimp simp: wpc_helper_def elim!: no_fail_pre) lemma wpc_helper_empty_fail_final: "empty_fail f \ wpc_helper (P, P') (Q, Q') (empty_fail f)" by (clarsimp simp: wpc_helper_def) lemma wpc_helper_validNF: "\Q\ g \S\! \ wpc_helper (P, P') (Q, Q') \P\ g \S\!" apply (clarsimp simp: wpc_helper_def) by (metis hoare_vcg_precond_imp no_fail_pre validNF_def) wpc_setup "\m. \P\ m \Q\" wpc_helper_valid wpc_setup "\m. \P\ m \Q\,\E\" wpc_helper_validE wpc_setup "\m. \P\ m \Q\,-" wpc_helper_validE_R wpc_setup "\m. \P\ m -,\E\" wpc_helper_validR_R wpc_setup "\m. no_fail P m" wpc_helper_no_fail_final wpc_setup "\m. empty_fail m" wpc_helper_empty_fail_final wpc_setup "\m. \P\ m \Q\!" wpc_helper_validNF lemma in_liftM: "((r, s') \ fst (liftM t f s)) = (\r'. (r', s') \ fst (f s) \ r = t r')" apply (simp add: liftM_def return_def bind_def) apply (simp add: Bex_def) done (* FIXME: eliminate *) lemmas handy_liftM_lemma = in_liftM lemma hoare_fun_app_wp[wp]: "\P\ f' x \Q'\ \ \P\ f' $ x \Q'\" "\P\ f x \Q\,\E\ \ \P\ f $ x \Q\,\E\" "\P\ f x \Q\,- \ \P\ f $ x \Q\,-" "\P\ f x -,\E\ \ \P\ f $ x -,\E\" by simp+ lemma hoare_validE_pred_conj: "\ \P\f\Q\,\E\; \P\f\R\,\E\ \ \ \P\f\Q And R\,\E\" unfolding valid_def validE_def by (simp add: split_def split: sum.splits) lemma hoare_validE_conj: "\ \P\f\Q\,\E\; \P\f\R\,\E\ \ \ \P\ f \\r s. Q r s \ R r s\,\E\" unfolding valid_def validE_def by (simp add: split_def split: sum.splits) lemmas hoare_valid_validE = valid_validE lemma liftE_validE_E [wp]: "\\\ liftE f -, \Q\" by (clarsimp simp: validE_E_def valid_def) declare validE_validE_E[wp_comb] (* * if_validE_E: * * \?P1 \ \?Q1\ ?f1 -, \?E\; \ ?P1 \ \?R1\ ?g1 -, \?E\\ \ \\s. (?P1 \ ?Q1 s) \ (\ ?P1 \ ?R1 s)\ if ?P1 then ?f1 else ?g1 -, \?E\ *) lemmas if_validE_E [wp_split] = validE_validE_E [OF hoare_vcg_if_splitE [OF validE_E_validE validE_E_validE]] lemma returnOk_E [wp]: "\\\ returnOk r -, \Q\" by (simp add: validE_E_def) wp lemma hoare_drop_imp: "\P\ f \Q\ \ \P\ f \\r s. R r s \ Q r s\" by (auto simp: valid_def) lemma hoare_drop_impE: "\\P\ f \\r. Q\, \E\\ \ \P\ f \\r s. R r s \ Q s\, \E\" by (simp add: validE_weaken) lemma hoare_drop_impE_R: "\P\ f \Q\,- \ \P\ f \\r s. R r s \ Q r s\, -" by (auto simp: validE_R_def validE_def valid_def split_def split: sum.splits) lemma hoare_drop_impE_E: "\P\ f -,\Q\ \ \P\ f -,\\r s. R r s \ Q r s\" by (auto simp: validE_E_def validE_def valid_def split_def split: sum.splits) lemmas hoare_drop_imps = hoare_drop_imp hoare_drop_impE_R hoare_drop_impE_E (*This is unsafe, but can be very useful when supplied as a comb rule.*) lemma hoare_drop_imp_conj[wp_unsafe]: "\P\ f \Q'\ \ \P'\ f \\rv s. (Q rv s \ Q'' rv s) \ Q''' rv s\ \ \P and P'\ f \\rv s. (Q rv s \ Q' rv s \ Q'' rv s) \ Q''' rv s\" by (auto simp: valid_def) lemmas hoare_drop_imp_conj'[wp_unsafe] = hoare_drop_imp_conj[where Q'''="\\", simplified] lemma bind_det_exec: "fst (a s) = {(r,s')} \ fst ((a >>= b) s) = fst (b r s')" by (simp add: bind_def) lemma in_bind_det_exec: "fst (a s) = {(r,s')} \ (s'' \ fst ((a >>= b) s)) = (s'' \ fst (b r s'))" by (simp add: bind_def) lemma exec_put: "(put s' >>= m) s = m () s'" by (simp add: bind_def put_def) lemma bind_execI: "\ (r'',s'') \ fst (f s); \x \ fst (g r'' s''). P x \ \ \x \ fst ((f >>= g) s). P x" by (force simp: in_bind split_def bind_def) lemma True_E_E [wp]: "\\\ f -,\\\\" by (auto simp: validE_E_def validE_def valid_def split: sum.splits) (* * \\x. \?B1 x\ ?g1 x -, \?E\; \?P\ ?f1 \?B1\, \?E\\ \ \?P\ ?f1 >>=E ?g1 -, \?E\ *) lemmas [wp_split] = validE_validE_E [OF hoare_vcg_seqE [OF validE_E_validE]] lemma case_option_wp: assumes x: "\x. \P x\ m x \Q\" assumes y: "\P'\ m' \Q\" shows "\\s. (x = None \ P' s) \ (x \ None \ P (the x) s)\ case_option m' m x \Q\" apply (cases x; simp) apply (rule y) apply (rule x) done lemma case_option_wpE: assumes x: "\x. \P x\ m x \Q\,\E\" assumes y: "\P'\ m' \Q\,\E\" shows "\\s. (x = None \ P' s) \ (x \ None \ P (the x) s)\ case_option m' m x \Q\,\E\" apply (cases x; simp) apply (rule y) apply (rule x) done lemma in_bindE: "(rv, s') \ fst ((f >>=E (\rv'. g rv')) s) = ((\ex. rv = Inl ex \ (Inl ex, s') \ fst (f s)) \ (\rv' s''. (rv, s') \ fst (g rv' s'') \ (Inr rv', s'') \ fst (f s)))" apply (rule iffI) apply (clarsimp simp: bindE_def bind_def) apply (case_tac a) apply (clarsimp simp: lift_def throwError_def return_def) apply (clarsimp simp: lift_def) apply safe apply (clarsimp simp: bindE_def bind_def) apply (erule rev_bexI) apply (simp add: lift_def throwError_def return_def) apply (clarsimp simp: bindE_def bind_def) apply (erule rev_bexI) apply (simp add: lift_def) done (* * \?P\ ?m1 -, \?E\ \ \?P\ liftME ?f1 ?m1 -, \?E\ *) lemmas [wp_split] = validE_validE_E [OF liftME_wp, simplified, OF validE_E_validE] lemma assert_A_True[simp]: "assert True = return ()" by (simp add: assert_def) lemma assert_wp [wp]: "\\s. P \ Q () s\ assert P \Q\" by (cases P, (simp add: assert_def | wp)+) lemma list_cases_wp: assumes a: "\P_A\ a \Q\" assumes b: "\x xs. ts = x#xs \ \P_B x xs\ b x xs \Q\" shows "\case_list P_A P_B ts\ case ts of [] \ a | x # xs \ b x xs \Q\" by (cases ts, auto simp: a b) (* FIXME: make wp *) lemma whenE_throwError_wp: "\\s. \Q \ P s\ whenE Q (throwError e) \\rv. P\, -" unfolding whenE_def by wpsimp lemma select_throwError_wp: "\\s. \x\S. Q x s\ select S >>= throwError -, \Q\" by (simp add: bind_def throwError_def return_def select_def validE_E_def validE_def valid_def) lemma assert_opt_wp[wp]: "\\s. x \ None \ Q (the x) s\ assert_opt x \Q\" by (case_tac x, (simp add: assert_opt_def | wp)+) lemma gets_the_wp[wp]: "\\s. (f s \ None) \ Q (the (f s)) s\ gets_the f \Q\" by (unfold gets_the_def, wp) lemma gets_the_wp': "\\s. \rv. f s = Some rv \ Q rv s\ gets_the f \Q\" unfolding gets_the_def by wpsimp lemma gets_map_wp: "\\s. f s p \ None \ Q (the (f s p)) s\ gets_map f p \Q\" unfolding gets_map_def by wpsimp lemma gets_map_wp'[wp]: "\\s. \rv. f s p = Some rv \ Q rv s\ gets_map f p \Q\" unfolding gets_map_def by wpsimp lemma no_fail_gets_map[wp]: "no_fail (\s. f s p \ None) (gets_map f p)" unfolding gets_map_def by wpsimp lemma hoare_vcg_set_pred_lift: assumes "\P x. m \ \s. P (f x s) \" shows "m \ \s. P {x. f x s} \" using assms[where P="\x . x"] assms[where P=Not] use_valid by (fastforce simp: valid_def elim!: rsubst[where P=P]) lemma hoare_vcg_set_pred_lift_mono: assumes f: "\x. m \ f x \" assumes mono: "\A B. A \ B \ P A \ P B" shows "m \ \s. P {x. f x s} \" by (fastforce simp: valid_def elim!: mono[rotated] dest: use_valid[OF _ f]) section "validNF Rules" subsection "Basic validNF theorems" lemma validNF [intro?]: "\ \ P \ f \ Q \; no_fail P f \ \ \ P \ f \ Q \!" by (clarsimp simp: validNF_def) lemma validNF_valid: "\ \ P \ f \ Q \! \ \ \ P \ f \ Q \" by (clarsimp simp: validNF_def) lemma validNF_no_fail: "\ \ P \ f \ Q \! \ \ no_fail P f" by (clarsimp simp: validNF_def) lemma snd_validNF: "\ \ P \ f \ Q \!; P s \ \ \ snd (f s)" by (clarsimp simp: validNF_def no_fail_def) lemma use_validNF: "\ (r', s') \ fst (f s); \ P \ f \ Q \!; P s \ \ Q r' s'" by (fastforce simp: validNF_def valid_def) subsection "validNF weakest pre-condition rules" lemma validNF_return [wp]: "\ P x \ return x \ P \!" by (wp validNF)+ lemma validNF_get [wp]: "\ \s. P s s \ get \ P \!" by (wp validNF)+ lemma validNF_put [wp]: "\ \s. P () x \ put x \ P \!" by (wp validNF)+ lemma validNF_K_bind [wp]: "\ P \ x \ Q \! \ \ P \ K_bind x f \ Q \!" by simp lemma validNF_fail [wp]: "\ \s. False \ fail \ Q \!" by (clarsimp simp: validNF_def fail_def no_fail_def) lemma validNF_prop [wp_unsafe]: "\ no_fail (\s. P) f \ \ \ \s. P \ f \ \rv s. P \!" by (wp validNF)+ lemma validNF_post_conj [intro!]: "\ \ P \ a \ Q \!; \ P \ a \ R \! \ \ \ P \ a \ Q And R \!" by (auto simp: validNF_def) lemma no_fail_or: "\no_fail P a; no_fail Q a\ \ no_fail (P or Q) a" by (clarsimp simp: no_fail_def) lemma validNF_pre_disj [intro!]: "\ \ P \ a \ R \!; \ Q \ a \ R \! \ \ \ P or Q \ a \ R \!" by (rule validNF) (auto dest: validNF_valid validNF_no_fail intro: no_fail_or) (* * Set up combination rules for WP, which also requires * a "wp_trip" rule for validNF. *) definition "validNF_property Q s b \ \ snd (b s) \ (\(r', s') \ fst (b s). Q r' s')" lemma validNF_is_triple [wp_trip]: "validNF P f Q = triple_judgement P f (validNF_property Q)" apply (clarsimp simp: validNF_def triple_judgement_def validNF_property_def) apply (auto simp: no_fail_def valid_def) done lemma validNF_weaken_pre[wp_pre]: "\\Q\ a \R\!; \s. P s \ Q s\ \ \P\ a \R\!" by (metis hoare_pre_imp no_fail_pre validNF_def) lemma validNF_post_comb_imp_conj: "\ \P'\ f \Q\!; \P\ f \Q'\!; \s. P s \ P' s \ \ \P\ f \\rv s. Q rv s \ Q' rv s\!" by (fastforce simp: validNF_def valid_def) lemma validNF_post_comb_conj_L: "\ \P'\ f \Q\!; \P\ f \Q'\ \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\!" apply (clarsimp simp: validNF_def valid_def no_fail_def) apply force done lemma validNF_post_comb_conj_R: "\ \P'\ f \Q\; \P\ f \Q'\! \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\!" apply (clarsimp simp: validNF_def valid_def no_fail_def) apply force done lemma validNF_post_comb_conj: "\ \P'\ f \Q\!; \P\ f \Q'\! \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\!" apply (clarsimp simp: validNF_def valid_def no_fail_def) apply force done lemma validNF_if_split [wp_split]: "\P \ \Q\ f \S\!; \ P \ \R\ g \S\!\ \ \\s. (P \ Q s) \ (\ P \ R s)\ if P then f else g \S\!" by simp lemma validNF_vcg_conj_lift: "\ \P\ f \Q\!; \P'\ f \Q'\! \ \ \\s. P s \ P' s\ f \\rv s. Q rv s \ Q' rv s\!" apply (subst bipred_conj_def[symmetric], rule validNF_post_conj) apply (erule validNF_weaken_pre, fastforce) apply (erule validNF_weaken_pre, fastforce) done lemma validNF_vcg_disj_lift: "\ \P\ f \Q\!; \P'\ f \Q'\! \ \ \\s. P s \ P' s\ f \\rv s. Q rv s \ Q' rv s\!" apply (clarsimp simp: validNF_def) apply safe apply (auto intro!: hoare_vcg_disj_lift)[1] apply (clarsimp simp: no_fail_def) done lemma validNF_vcg_all_lift [wp]: "\ \x. \P x\ f \Q x\! \ \ \\s. \x. P x s\ f \\rv s. \x. Q x rv s\!" apply atomize apply (rule validNF) apply (clarsimp simp: validNF_def) apply (rule hoare_vcg_all_lift) apply force apply (clarsimp simp: no_fail_def validNF_def) done lemma validNF_bind [wp_split]: "\ \x. \B x\ g x \C\!; \A\ f \B\! \ \ \A\ do x \ f; g x od \C\!" apply (rule validNF) apply (metis validNF_valid hoare_seq_ext) apply (clarsimp simp: no_fail_def validNF_def bind_def' valid_def) apply blast done lemmas validNF_seq_ext = validNF_bind subsection "validNF compound rules" lemma validNF_state_assert [wp]: "\ \s. P () s \ G s \ state_assert G \ P \!" apply (rule validNF) apply wpsimp apply (clarsimp simp: no_fail_def state_assert_def bind_def' assert_def return_def get_def) done lemma validNF_modify [wp]: "\ \s. P () (f s) \ modify f \ P \!" apply (clarsimp simp: modify_def) apply wp done lemma validNF_gets [wp]: "\\s. P (f s) s\ gets f \P\!" apply (clarsimp simp: gets_def) apply wp done lemma validNF_condition [wp]: "\ \ Q \ A \P\!; \ R \ B \P\!\ \ \\s. if C s then Q s else R s\ condition C A B \P\!" apply rule apply (drule validNF_valid)+ apply (erule (1) condition_wp) apply (drule validNF_no_fail)+ apply (clarsimp simp: no_fail_def condition_def) done lemma validNF_alt_def: "validNF P m Q = (\s. P s \ ((\(r', s') \ fst (m s). Q r' s') \ \ snd (m s)))" by (fastforce simp: validNF_def valid_def no_fail_def) lemma validNF_assert [wp]: "\ (\s. P) and (R ()) \ assert P \ R \!" apply (rule validNF) apply (clarsimp simp: valid_def in_return) apply (clarsimp simp: no_fail_def return_def) done lemma validNF_false_pre: "\ \_. False \ P \ Q \!" by (clarsimp simp: validNF_def no_fail_def) lemma validNF_chain: "\\P'\ a \R'\!; \s. P s \ P' s; \r s. R' r s \ R r s\ \ \P\ a \R\!" by (fastforce simp: validNF_def valid_def no_fail_def Ball_def) lemma validNF_case_prod [wp]: "\ \x y. validNF (P x y) (B x y) Q \ \ validNF (case_prod P v) (case_prod (\x y. B x y) v) Q" by (metis prod.exhaust split_conv) lemma validE_NF_case_prod [wp]: "\ \a b. \P a b\ f a b \Q\, \E\! \ \ \case x of (a, b) \ P a b\ case x of (a, b) \ f a b \Q\, \E\!" apply (clarsimp simp: validE_NF_alt_def) apply (erule validNF_case_prod) done lemma no_fail_is_validNF_True: "no_fail P s = (\ P \ s \ \_ _. True \!)" by (clarsimp simp: no_fail_def validNF_def valid_def) subsection "validNF reasoning in the exception monad" lemma validE_NF [intro?]: "\ \ P \ f \ Q \,\ E \; no_fail P f \ \ \ P \ f \ Q \,\ E \!" apply (clarsimp simp: validE_NF_def) done lemma validE_NF_valid: "\ \ P \ f \ Q \,\ E \! \ \ \ P \ f \ Q \,\ E \" apply (clarsimp simp: validE_NF_def) done lemma validE_NF_no_fail: "\ \ P \ f \ Q \,\ E \! \ \ no_fail P f" apply (clarsimp simp: validE_NF_def) done lemma validE_NF_weaken_pre[wp_pre]: "\\Q\ a \R\,\E\!; \s. P s \ Q s\ \ \P\ a \R\,\E\!" apply (clarsimp simp: validE_NF_alt_def) apply (erule validNF_weaken_pre) apply simp done lemma validE_NF_post_comb_conj_L: "\ \P\ f \Q\, \ E \!; \P'\ f \Q'\, \ \_ _. True \ \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\, \ E \!" apply (clarsimp simp: validE_NF_alt_def validE_def validNF_def valid_def no_fail_def split: sum.splits) apply force done lemma validE_NF_post_comb_conj_R: "\ \P\ f \Q\, \ \_ _. True \; \P'\ f \Q'\, \ E \! \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\, \ E \!" apply (clarsimp simp: validE_NF_alt_def validE_def validNF_def valid_def no_fail_def split: sum.splits) apply force done lemma validE_NF_post_comb_conj: "\ \P\ f \Q\, \ E \!; \P'\ f \Q'\, \ E \! \ \ \\s. P s \ P' s \ f \\rv s. Q rv s \ Q' rv s\, \ E \!" apply (clarsimp simp: validE_NF_alt_def validE_def validNF_def valid_def no_fail_def split: sum.splits) apply force done lemma validE_NF_chain: "\\P'\ a \R'\,\E'\!; \s. P s \ P' s; \r' s'. R' r' s' \ R r' s'; \r'' s''. E' r'' s'' \ E r'' s''\ \ \\s. P s \ a \\r' s'. R r' s'\,\\r'' s''. E r'' s''\!" by (fastforce simp: validE_NF_def validE_def2 no_fail_def Ball_def split: sum.splits) lemma validE_NF_bind_wp [wp]: "\\x. \B x\ g x \C\, \E\!; \A\ f \B\, \E\!\ \ \A\ f >>=E (\x. g x) \C\, \E\!" apply (unfold validE_NF_alt_def bindE_def) apply (rule validNF_bind [rotated]) apply assumption apply (clarsimp simp: lift_def throwError_def split: sum.splits) apply wpsimp done lemma validNF_catch [wp]: "\\x. \E x\ handler x \Q\!; \P\ f \Q\, \E\!\ \ \P\ f (\x. handler x) \Q\!" apply (unfold validE_NF_alt_def catch_def) apply (rule validNF_bind [rotated]) apply assumption apply (clarsimp simp: lift_def throwError_def split: sum.splits) apply wp done lemma validNF_throwError [wp]: "\E e\ throwError e \P\, \E\!" by (unfold validE_NF_alt_def throwError_def o_def) wpsimp lemma validNF_returnOk [wp]: "\P e\ returnOk e \P\, \E\!" by (clarsimp simp: validE_NF_alt_def returnOk_def) wpsimp lemma validNF_whenE [wp]: "(P \ \Q\ f \R\, \E\!) \ \if P then Q else R ()\ whenE P f \R\, \E\!" unfolding whenE_def by clarsimp wp lemma validNF_nobindE [wp]: "\ \B\ g \C\,\E\!; \A\ f \\r s. B s\,\E\! \ \ \A\ doE f; g odE \C\,\E\!" by clarsimp wp text \ Setup triple rules for @{term validE_NF} so that we can use wp combinator rules. \ definition "validE_NF_property Q E s b \ \ snd (b s) \ (\(r', s') \ fst (b s). case r' of Inl x \ E x s' | Inr x \ Q x s')" lemma validE_NF_is_triple [wp_trip]: "validE_NF P f Q E = triple_judgement P f (validE_NF_property Q E)" apply (clarsimp simp: validE_NF_def validE_def2 no_fail_def triple_judgement_def validE_NF_property_def split: sum.splits) apply blast done lemma validNF_cong: "\ \s. P s = P' s; \s. P s \ m s = m' s; \r' s' s. \ P s; (r', s') \ fst (m s) \ \ Q r' s' = Q' r' s' \ \ (\ P \ m \ Q \!) = (\ P' \ m' \ Q' \!)" by (fastforce simp: validNF_alt_def) lemma validE_NF_liftE [wp]: "\P\ f \Q\! \ \P\ liftE f \Q\,\E\!" by (wpsimp simp: validE_NF_alt_def liftE_def) lemma validE_NF_handleE' [wp]: "\ \x. \F x\ handler x \Q\,\E\!; \P\ f \Q\,\F\! \ \ \P\ f (\x. handler x) \Q\,\E\!" apply (unfold validE_NF_alt_def handleE'_def) apply (rule validNF_bind [rotated]) apply assumption apply (clarsimp split: sum.splits) apply wpsimp done lemma validE_NF_handleE [wp]: "\ \x. \F x\ handler x \Q\,\E\!; \P\ f \Q\,\F\! \ \ \P\ f handler \Q\,\E\!" apply (unfold handleE_def) apply (metis validE_NF_handleE') done lemma validE_NF_condition [wp]: "\ \ Q \ A \P\,\ E \!; \ R \ B \P\,\ E \!\ \ \\s. if C s then Q s else R s\ condition C A B \P\,\ E \!" apply rule apply (drule validE_NF_valid)+ apply wp apply (drule validE_NF_no_fail)+ apply (clarsimp simp: no_fail_def condition_def) done text \Strengthen setup.\ context strengthen_implementation begin lemma strengthen_hoare [strg]: "(\r s. st F (\) (Q r s) (R r s)) \ st F (\) (\P\ f \Q\) (\P\ f \R\)" by (cases F, auto elim: hoare_strengthen_post) lemma strengthen_validE_R_cong[strg]: "(\r s. st F (\) (Q r s) (R r s)) \ st F (\) (\P\ f \Q\, -) (\P\ f \R\, -)" by (cases F, auto intro: hoare_post_imp_R) lemma strengthen_validE_cong[strg]: "(\r s. st F (\) (Q r s) (R r s)) \ (\r s. st F (\) (S r s) (T r s)) \ st F (\) (\P\ f \Q\, \S\) (\P\ f \R\, \T\)" by (cases F, auto elim: hoare_post_impErr) lemma strengthen_validE_E_cong[strg]: "(\r s. st F (\) (S r s) (T r s)) \ st F (\) (\P\ f -, \S\) (\P\ f -, \T\)" by (cases F, auto elim: hoare_post_impErr simp: validE_E_def) lemma wpfix_strengthen_hoare: "(\s. st (\ F) (\) (P s) (P' s)) \ (\r s. st F (\) (Q r s) (Q' r s)) \ st F (\) (\P\ f \Q\) (\P'\ f \Q'\)" by (cases F, auto elim: hoare_chain) lemma wpfix_strengthen_validE_R_cong: "(\s. st (\ F) (\) (P s) (P' s)) \ (\r s. st F (\) (Q r s) (Q' r s)) \ st F (\) (\P\ f \Q\, -) (\P'\ f \Q'\, -)" by (cases F, auto elim: hoare_chainE simp: validE_R_def) lemma wpfix_strengthen_validE_cong: "(\s. st (\ F) (\) (P s) (P' s)) \ (\r s. st F (\) (Q r s) (R r s)) \ (\r s. st F (\) (S r s) (T r s)) \ st F (\) (\P\ f \Q\, \S\) (\P'\ f \R\, \T\)" by (cases F, auto elim: hoare_chainE) lemma wpfix_strengthen_validE_E_cong: "(\s. st (\ F) (\) (P s) (P' s)) \ (\r s. st F (\) (S r s) (T r s)) \ st F (\) (\P\ f -, \S\) (\P'\ f -, \T\)" by (cases F, auto elim: hoare_chainE simp: validE_E_def) lemma wpfix_no_fail_cong: "(\s. st (\ F) (\) (P s) (P' s)) \ st F (\) (no_fail P f) (no_fail P' f)" by (cases F, auto elim: no_fail_pre) lemmas nondet_wpfix_strgs = wpfix_strengthen_validE_R_cong wpfix_strengthen_validE_E_cong wpfix_strengthen_validE_cong wpfix_strengthen_hoare wpfix_no_fail_cong end lemmas nondet_wpfix_strgs[wp_fix_strgs] = strengthen_implementation.nondet_wpfix_strgs end