(* * Copyright 2014, NICTA * * 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(NICTA_BSD) *) (* A theory of rewriting under refinement. *) theory MonadicRewrite imports "Monad_WP/NonDetMonadVCG" Corres_UL EmptyFailLib LemmaBucket begin definition monadic_rewrite :: "bool \ bool \ ('a \ bool) \ ('a, 'b) nondet_monad \ ('a, 'b) nondet_monad \ bool" where "monadic_rewrite F E P f g \ \s. P s \ (F \ \ snd (f s)) \ (E \ f s = g s) \ (\ E \ fst (g s) \ fst (f s) \ (snd (g s) \ snd (f s)))" (* FIXME: also in Retype_C *) lemma snd_bind: "snd ((a >>= b) s) = (snd (a s) \ (\(r, s') \ fst (a s). snd (b r s')))" by (auto simp add: bind_def split_def) lemma monadic_rewrite_bind: "\ monadic_rewrite F E P f g; \x. monadic_rewrite F E (Q x) (h x) (j x); \R\ g \Q\ \ \ monadic_rewrite F E (P and R) (f >>= (\x. h x)) (g >>= (\x. j x))" apply (cases E) apply (clarsimp simp: monadic_rewrite_def snd_bind imp_conjL) apply (drule spec, drule(1) mp, clarsimp) apply (rule bind_apply_cong) apply simp apply (frule(2) use_valid) apply fastforce apply (clarsimp simp: monadic_rewrite_def snd_bind imp_conjL) apply (simp add: bind_def split_def) apply (rule conjI) apply (rule UN_mono) apply simp apply clarsimp apply (frule(2) use_valid) apply fastforce apply (rule conjI) apply fastforce apply clarsimp apply (frule(2) use_valid) apply fastforce done lemma monadic_rewrite_refl: "monadic_rewrite F E \ f f" by (simp add: monadic_rewrite_def) lemma monadic_rewrite_bindE: "\ monadic_rewrite F E P f g; \x. monadic_rewrite F E (Q x) (h x) (j x); \R\ g \Q\,- \ \ monadic_rewrite F E (P and R) (f >>=E (\x. h x)) (g >>=E (\x. j x))" apply (simp add: bindE_def) apply (erule monadic_rewrite_bind) defer apply (simp add: validE_R_def validE_def) apply (case_tac x, simp_all add: lift_def monadic_rewrite_refl) done lemma monadic_rewrite_catch: "\ monadic_rewrite F E P f g; \x. monadic_rewrite F E (Q x) (h x) (j x); \R\ g -,\Q\ \ \ monadic_rewrite F E (P and R) (f (\x. h x)) (g (\x. j x))" apply (simp add: catch_def) apply (erule monadic_rewrite_bind) defer apply (simp add: validE_E_def validE_def) apply (case_tac x, simp_all add: lift_def monadic_rewrite_refl) done lemma monadic_rewrite_symb_exec_pre: assumes inv: "\s. \(=) s\ g \\r. (=) s\" and ef: "empty_fail g" and rv: "\P\ g \\y s. y \ S\" and h': "\y. y \ S \ h y = h'" shows "monadic_rewrite True True P (g >>= h) h'" proof - have P: "\s v. \ P s; v \ fst (g s) \ \ split h v = h' s" apply clarsimp apply (frule use_valid[OF _ inv], rule refl) apply (frule(1) use_valid[OF _ rv]) apply (simp add: h') done show ?thesis apply (clarsimp simp: monadic_rewrite_def bind_def P image_constant_conv cong: image_cong) apply (drule empty_failD2[OF ef]) apply (clarsimp simp: prod_eq_iff split: if_split_asm) done qed lemma monadic_rewrite_trans: "\ monadic_rewrite F E P f g; monadic_rewrite F E Q g h \ \ monadic_rewrite F E (P and Q) f h" by (auto simp add: monadic_rewrite_def) lemma singleton_eq_imp_helper: "v \ {x} \ h v = h x" by simp lemmas monadic_rewrite_symb_exec = monadic_rewrite_symb_exec_pre [OF _ _ _ singleton_eq_imp_helper, THEN monadic_rewrite_trans, simplified] lemma eq_UNIV_imp_helper: "v \ UNIV \ x = x" by simp lemmas monadic_rewrite_symb_exec2 = monadic_rewrite_symb_exec_pre[OF _ _ _ eq_UNIV_imp_helper, where P=\, simplified, THEN monadic_rewrite_trans] lemma monadic_rewrite_imp: "\ monadic_rewrite F E Q f g; \s. P s \ Q s \ \ monadic_rewrite F E P f g" by (auto simp add: monadic_rewrite_def) lemmas monadic_rewrite_bind_tail = monadic_rewrite_bind [OF monadic_rewrite_refl, simplified pred_and_true_var] lemmas monadic_rewrite_bind_head = monadic_rewrite_bind [OF _ monadic_rewrite_refl hoare_vcg_prop, simplified pred_and_true] lemma monadic_rewrite_bind2: "\ monadic_rewrite F E P f g; \x. monadic_rewrite F E (Q x) (h x) (j x); \R\ f \Q\ \ \ monadic_rewrite F E (P and R) (f >>= (\x. h x)) (g >>= (\x. j x))" apply (rule monadic_rewrite_imp) apply (rule monadic_rewrite_trans) apply (erule(1) monadic_rewrite_bind_tail) apply (erule monadic_rewrite_bind_head) apply simp done lemma monadic_rewrite_if: "\ P \ monadic_rewrite F E Q a c; \ P \ monadic_rewrite F E R b d \ \ monadic_rewrite F E (\s. (P \ Q s) \ (\ P \ R s)) (If P a b) (If P c d)" by (cases P, simp_all) lemma monadic_rewrite_liftM: "monadic_rewrite F E P f g \ monadic_rewrite F E P (liftM fn f) (liftM fn g)" apply (simp add: liftM_def) apply (erule monadic_rewrite_bind_head) done lemmas monadic_rewrite_liftE = monadic_rewrite_liftM[where fn=Inr, folded liftE_liftM] lemma monadic_rewrite_from_simple: "P \ f = g \ monadic_rewrite F E (\_. P) f g" by (simp add: monadic_rewrite_def) lemma monadic_rewrite_gen_asm: "\ P \ monadic_rewrite F E Q f g \ \ monadic_rewrite F E ((\_. P) and Q) f g" by (auto simp add: monadic_rewrite_def) lemma monadic_rewrite_assert: "\ Q \ monadic_rewrite True E P (f ()) g \ \ monadic_rewrite True E (\s. Q \ P s) (assert Q >>= f) g" apply (simp add: assert_def split: if_split) apply (simp add: monadic_rewrite_def fail_def) done lemma monadic_rewrite_drop_modify: "monadic_rewrite F E (\s. f s = s) (modify f >>= v) (v ())" by (simp add: monadic_rewrite_def bind_def simpler_modify_def) lemma monadic_rewrite_symb_exec_r: "\ \s. \(=) s\ m \\r. (=) s\; no_fail P' m; \rv. monadic_rewrite F False (Q rv) x (y rv); \P\ m \Q\ \ \ monadic_rewrite F False (P and P') x (m >>= y)" apply (clarsimp simp: monadic_rewrite_def bind_def) apply (drule(1) no_failD) apply (subgoal_tac "\v \ fst (m s). Q (fst v) (snd v) \ snd v = s") apply fastforce apply clarsimp apply (frule(2) use_valid) apply (frule use_valid, assumption, rule refl) apply simp done lemma monadic_rewrite_symb_exec_r': "\ \s. \(=) s\ m \\r. (=) s\; no_fail P m; \rv. monadic_rewrite F False (Q rv) x (y rv); \P\ m \Q\ \ \ monadic_rewrite F False P x (m >>= y)" apply (rule monadic_rewrite_imp) apply (rule monadic_rewrite_symb_exec_r; assumption) apply simp done lemma monadic_rewrite_symb_exec_l'': "\ \s. \(=) s\ m \\r. (=) s\; empty_fail m; \ F \ no_fail P' m; \rv. monadic_rewrite F False (Q rv) (x rv) y; \P\ m \Q\ \ \ monadic_rewrite F False (P and P') (m >>= x) y" apply (clarsimp simp: monadic_rewrite_def bind_def) apply (subgoal_tac "\ snd (m s)") apply (subgoal_tac "\v \ fst (m s). Q (fst v) (snd v) \ snd v = s") apply (frule(1) empty_failD2) apply (clarsimp simp: split_def) apply fastforce apply clarsimp apply (frule(2) use_valid) apply (frule use_valid, assumption, rule refl) apply simp apply (cases F, simp_all add: no_failD) done lemma monadic_rewrite_symb_exec_l': "\ \P. \P\ m \\r. P\; empty_fail m; \ F \ no_fail P' m; \rv. monadic_rewrite F E (Q rv) (x rv) y; \P\ m \Q\ \ \ monadic_rewrite F E (P and P') (m >>= x) y" apply (cases E) apply (clarsimp simp: monadic_rewrite_def bind_def prod_eq_iff) apply (subgoal_tac "\ snd (m s)") apply (simp add: empty_fail_def, drule_tac x=s in spec) apply (subgoal_tac "\(rv, s') \ fst (m s). x rv s' = y s") apply (rule conjI) apply (rule equalityI) apply (clarsimp simp: Ball_def) apply (fastforce simp: Ball_def elim!: nonemptyE elim: rev_bexI) apply (simp add: Bex_def Ball_def cong: conj_cong) apply auto[1] apply clarsimp apply (drule(1) in_inv_by_hoareD) apply (frule(2) use_valid) apply (clarsimp simp: Ball_def prod_eq_iff) apply (clarsimp simp: no_fail_def) apply simp apply (rule monadic_rewrite_symb_exec_l'', assumption+) done (* FIXME this should replace monadic_rewrite_symb_exec_l' as it preserves names, and this approach should be used everywhere else anyhow, however that breaks proofs relying on arbitrarily generated names, so will be dealt with in future *) lemma monadic_rewrite_symb_exec_l'_preserve_names: "\ \P. \P\ m \\r. P\; empty_fail m; \ F \ no_fail P' m; \rv. monadic_rewrite F E (Q rv) (x rv) y; \P\ m \Q\ \ \ monadic_rewrite F E (P and P') (m >>= (\rv. x rv)) y" by (rule monadic_rewrite_symb_exec_l') (* FIXME merge into below upon change-over desribed above *) lemmas monadic_rewrite_symb_exec_l'_TT = monadic_rewrite_symb_exec_l'_preserve_names[where P'="\" and F=True, simplified] lemmas monadic_rewrite_symb_exec_l = monadic_rewrite_symb_exec_l''[where F=True and P'=\, simplified] monadic_rewrite_symb_exec_l''[where F=False, simplified simp_thms] lemma monadic_rewrite_alternative_rhs: "\ monadic_rewrite F E P a b; monadic_rewrite F E Q a c \ \ monadic_rewrite F E (P and Q) a (b \ c)" apply (clarsimp simp: monadic_rewrite_def alternative_def) apply auto done lemma monadic_rewrite_rdonly_bind: "\ \s. \(=) s\ f \\rv. (=) s\ \ \ monadic_rewrite F False \ (alternative (f >>= (\x. g x)) h) (f >>= (\x. alternative (g x) h))" apply (clarsimp simp: monadic_rewrite_def bind_def alternative_def imp_conjL) apply (subgoal_tac "\x \ fst (f s). snd x = s") apply (simp add: image_image split_def cong: image_cong) apply fastforce apply clarsimp apply (frule use_valid, (assumption | rule refl | simp)+) done lemmas monadic_rewrite_rdonly_bind_l = monadic_rewrite_trans [OF monadic_rewrite_rdonly_bind] lemma monadic_rewrite_if_rhs: "\ P \ monadic_rewrite F E Q a b; \ P \ monadic_rewrite F E R a c \ \ monadic_rewrite F E (\s. (P \ Q s) \ (\ P \ R s)) a (If P b c)" by (cases P, simp_all) lemma monadic_rewrite_transverse: "\ monadic_rewrite False True Q c b; monadic_rewrite F E P a b \ \ monadic_rewrite F E (P and Q) a c" by (auto simp add: monadic_rewrite_def) lemma monadic_rewrite_alternative_l: "monadic_rewrite F False \ (alternative f g) g" by (clarsimp simp: monadic_rewrite_def alternative_def) lemma monadic_rewrite_introduce_alternative: "\ f = f'; monadic_rewrite F E P (alternative f' f) g \ \ monadic_rewrite F E P f g" by (simp add: alternative_def) lemma monadic_rewrite_modify_noop: "monadic_rewrite F E (\s. f s = s) (modify f) (return ())" by (clarsimp simp: monadic_rewrite_def simpler_modify_def return_def) lemma monadic_rewrite_split_fn: "\ monadic_rewrite F E P (liftM fn a) c; \rv. monadic_rewrite F E (Q rv) (b rv) (d (fn rv)); \R\ a \Q\ \ \ monadic_rewrite F E (P and R) (a >>= b) (c >>= d)" apply (rule monadic_rewrite_imp) apply (rule monadic_rewrite_trans[rotated]) apply (erule monadic_rewrite_bind_head) apply (simp add: liftM_def) apply (erule(1) monadic_rewrite_bind_tail) apply simp done lemma monadic_rewrite_pick_alternative_1: "monadic_rewrite F False \ (alternative f g) f" by (auto simp add: monadic_rewrite_def alternative_def) lemma monadic_rewrite_pick_alternative_2: "monadic_rewrite F False \ (alternative f g) g" by (auto simp add: monadic_rewrite_def alternative_def) lemma monadic_rewrite_weaken: "monadic_rewrite (F \ F') (E \ E') P f g \ monadic_rewrite F' E' P f g" apply (clarsimp simp add: monadic_rewrite_def) apply auto done lemma monadic_rewrite_is_refl: "x = y \ monadic_rewrite F E \ x y" by (simp add: monadic_rewrite_refl) lemma monadic_rewrite_refl3: "[| !!s. P s ==> f s = g s |] ==> monadic_rewrite F E P f g" by (simp add: monadic_rewrite_def) lemmas monadic_rewrite_refl2 = monadic_rewrite_refl3[where P=\] lemma monadic_rewrite_cases: "\ P \ monadic_rewrite F E Q a b; \ P \ monadic_rewrite F E R a b \ \ monadic_rewrite F E (\s. (P \ Q s) \ (\ P \ R s)) a b" by (cases P, simp_all) lemma monadic_rewrite_symb_exec_l_known: "\ \s. \(=) s\ m \\r. (=) s\; empty_fail m; monadic_rewrite True False Q (x rv) y; \P\ m \\rv' s. rv' = rv \ Q s\ \ \ monadic_rewrite True False P (m >>= x) y" apply (erule(1) monadic_rewrite_symb_exec_l) apply (rule_tac P="rva = rv" in monadic_rewrite_gen_asm) apply simp apply (erule hoare_strengthen_post) apply simp done lemma monadic_rewrite_gets_the_known_v: "monadic_rewrite F E (\s. f s = Some v) (gets_the f) (return v)" by (simp add: monadic_rewrite_def gets_the_def exec_gets assert_opt_def) lemma monadic_rewrite_gets_the_walk: "\ \x. monadic_rewrite True False (P x) (g x) (gets_the pf >>= g' x); \Q. \\s. Q (pf s)\ f \\rv s. Q (pf s)\; \R\ f \P\; empty_fail f \ \ monadic_rewrite True False R (f >>= g) (do v \ gets_the pf; x \ f; g' x v od)" apply (rule monadic_rewrite_imp) apply (rule monadic_rewrite_trans) apply (erule(1) monadic_rewrite_bind_tail) apply (simp add: gets_the_def bind_assoc) apply (rule monadic_rewrite_symb_exec_r, wp+) apply (rule monadic_rewrite_trans) apply (rule monadic_rewrite_bind_tail) apply (rule_tac rv=rv in monadic_rewrite_symb_exec_l_known, (wp empty_fail_gets)+) apply (rule monadic_rewrite_refl) apply wp apply assumption apply (rule_tac P="rv = None" in monadic_rewrite_cases[where Q=\]) apply (simp add: assert_opt_def) apply (clarsimp simp: monadic_rewrite_def fail_def snd_bind) apply (rule ccontr, drule(1) empty_failD2) apply clarsimp apply (simp add: assert_opt_def case_option_If2) apply (rule monadic_rewrite_refl) apply wp apply simp done lemma monadic_rewrite_alternatives: "\ monadic_rewrite E F P a c; monadic_rewrite E F Q b d \ \ monadic_rewrite E F (P and Q) (a \ b) (c \ d)" by (auto simp: monadic_rewrite_def alternative_def) lemma monadic_rewrite_weaken2: "monadic_rewrite F E P f g \ monadic_rewrite F' E' ((\_. (F \ F') \ (E' \ E)) and P) f g" apply (rule monadic_rewrite_gen_asm) apply (rule monadic_rewrite_weaken[where F=F and E=E]) apply auto done lemma monadic_rewrite_case_sum: "\ \v. x = Inl v \ monadic_rewrite F E (P v) (a v) (c v); \v. x = Inr v \ monadic_rewrite F E (Q v) (b v) (d v) \ \ monadic_rewrite F E (\s. (\ isRight x \ P (theLeft x) s) \ (isRight x \ Q (theRight x) s)) (case_sum a b x) (case_sum c d x)" by (cases x, simp_all add: isRight_def) lemma monadic_rewrite_add_gets: "monadic_rewrite F E \ m (gets f >>= (\_. m))" by (simp add: monadic_rewrite_def exec_gets) lemma monadic_rewrite_add_assert: "monadic_rewrite F E (\s. P) m (assert P >>= (\_. m))" by (simp add: monadic_rewrite_def) lemma monadic_rewrite_gets_known: "monadic_rewrite F E (\s. f s = rv) (gets f >>= m) (m rv)" by (simp add: monadic_rewrite_def exec_gets) lemma monadic_rewrite_name_pre: "\ \s. P s \ monadic_rewrite F E ((=) s) f g \ \ monadic_rewrite F E P f g" by (auto simp add: monadic_rewrite_def) lemma monadic_rewrite_named_bindE: "\ monadic_rewrite F E ((=) s) f f'; \rv s'. (Inr rv, s') \ fst (f' s) \ monadic_rewrite F E ((=) s') (g rv) (g' rv) \ \ monadic_rewrite F E ((=) s) (f >>=E (\rv. g rv)) (f' >>=E g')" apply (rule monadic_rewrite_imp) apply (erule_tac R="(=) s" and Q="\rv s'. (Inr rv, s') \ fst (f' s)" in monadic_rewrite_bindE) apply (rule monadic_rewrite_name_pre) apply clarsimp apply (clarsimp simp add: validE_R_def validE_def valid_def split: sum.split) apply simp done lemmas monadic_rewrite_named_if = monadic_rewrite_if[where Q="(=) s" and R="(=) s", simplified] for s lemma monadic_rewrite_if_lhs: "\ P \ monadic_rewrite F E Q b a; \ P \ monadic_rewrite F E R c a \ \ monadic_rewrite F E (\s. (P \ Q s) \ (\ P \ R s)) (If P b c) a" by (cases P, simp_all) lemma monadic_rewrite_to_eq: "monadic_rewrite False True \ f g ==> f = g" by (simp add: monadic_rewrite_def fun_eq_iff) lemma corres_underlyingI: assumes rv: "\s t rv' t'. \(s, t) \ R; P s; P' t; (rv', t') \ fst (c t)\ \ \(rv, s') \ fst (a s). (s', t') \ R \ r rv rv'" and nf: "\s t. \(s, t) \ R; P s; P' t; nf'\ \ \ snd (c t)" shows "corres_underlying R nf nf' r P P' a c" unfolding corres_underlying_def using rv nf by (auto simp: split_def) lemma corres_underlyingE: assumes cul: "corres_underlying R nf nf' r P P' a c" and xin: "(s, t) \ R" "P s" "P' t" "(rv', t') \ fst (c t)" and rl: "\s' rv. \nf' \ \ snd (c t); (rv, s') \ fst (a s); (s', t') \ R; r rv rv'\ \ Q" and nf: "nf \ \ snd (a s)" shows "Q" using cul xin nf unfolding corres_underlying_def by (fastforce simp: split_def intro: rl) (* Above here is generic *) lemma monadic_rewrite_corres: assumes cu: "corres_underlying R False nf' r P P' a' c" and me: "monadic_rewrite False True Q a a'" shows "corres_underlying R False nf' r (P and Q) P' a c" proof (rule corres_underlyingI) fix s t rv' t' assume st: "(s, t) \ R" and pq: "(P and Q) s" and pt: "P' t" and ct: "(rv', t') \ fst (c t)" from pq have Ps: "P s" and Qs: "Q s" by simp_all from cu st Ps pt ct obtain s' rv where as': "(rv, s') \ fst (a' s)" and rest: "nf' \ \ snd (c t)" "(s', t') \ R" "r rv rv'" by (fastforce elim: corres_underlyingE) from me st Qs as' have as: "(rv, s') \ fst (a s)" by (clarsimp simp: monadic_rewrite_def) with rest show "\(rv, s')\fst (a s). (s', t') \ R \ r rv rv'" by auto next fix s t assume "(s, t) \ R" "(P and Q) s" "P' t" "nf'" thus "\ snd (c t)" using cu by (fastforce simp: corres_underlying_def split_def) qed lemma monadic_rewrite_refine_valid: "monadic_rewrite F E P f g \ \P'\ f \Q\ \ F \ no_fail P'' f \ \P and P' and P''\ g \Q\" apply (clarsimp simp: monadic_rewrite_def valid_def no_fail_def imp_conjL) apply (drule spec, drule(1) mp)+ apply (clarsimp simp: Ball_def) apply auto done lemma monadic_rewrite_refine_validE_R: "monadic_rewrite F E P f g \ \P'\ f \Q\, - \ F \ no_fail P'' f \ \P and P' and P''\ g \Q\, -" by (simp add: validE_R_def validE_def monadic_rewrite_refine_valid) lemma wpc_helper_monadic_rewrite: "monadic_rewrite F E Q' m m' \ wpc_helper (P, P') (Q, {s. Q' s}) (monadic_rewrite F E (\s. s \ P') m m')" apply (clarsimp simp: wpc_helper_def) apply (erule monadic_rewrite_imp) apply auto done wpc_setup "\m. monadic_rewrite F E Q' m m'" wpc_helper_monadic_rewrite wpc_setup "\m. monadic_rewrite F E Q' (m >>= c) m'" wpc_helper_monadic_rewrite end