(* * 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) *) theory WhileLoopRules imports "wp/NonDetMonadVCG" begin section "Well-ordered measures" (* A version of "measure" that takes any wellorder, instead of * being fixed to "nat". *) definition measure' :: "('a \ 'b::wellorder) => ('a \ 'a) set" where "measure' = (\f. {(a, b). f a < f b})" lemma in_measure'[simp, code_unfold]: "((x,y) : measure' f) = (f x < f y)" by (simp add:measure'_def) lemma wf_measure' [iff]: "wf (measure' f)" apply (clarsimp simp: measure'_def) apply (insert wf_inv_image [OF wellorder_class.wf, where f=f]) apply (clarsimp simp: inv_image_def) done lemma wf_wellorder_measure: "wf {(a, b). (M a :: 'a :: wellorder) < M b}" apply (subgoal_tac "wf (inv_image ({(a, b). a < b}) M)") apply (clarsimp simp: inv_image_def) apply (rule wf_inv_image) apply (rule wellorder_class.wf) done section "whileLoop lemmas" text {* The following @{const whileLoop} definitions with additional invariant/variant annotations allow the user to annotate @{const whileLoop} terms with information that can be used by automated tools. *} definition "whileLoop_inv (C :: 'a \ 'b \ bool) B x (I :: 'a \ 'b \ bool) (R :: (('a \ 'b) \ ('a \ 'b)) set) \ whileLoop C B x" definition "whileLoopE_inv (C :: 'a \ 'b \ bool) B x (I :: 'a \ 'b \ bool) (R :: (('a \ 'b) \ ('a \ 'b)) set) \ whileLoopE C B x" lemma whileLoop_add_inv: "whileLoop B C = (\x. whileLoop_inv B C x I (measure' M))" by (clarsimp simp: whileLoop_inv_def) lemma whileLoopE_add_inv: "whileLoopE B C = (\x. whileLoopE_inv B C x I (measure' M))" by (clarsimp simp: whileLoopE_inv_def) subsection "Simple base rules" lemma whileLoop_terminates_unfold: "\ whileLoop_terminates C B r s; (r', s') \ fst (B r s); C r s \ \ whileLoop_terminates C B r' s'" apply (erule whileLoop_terminates.cases) apply simp apply force done lemma snd_whileLoop_first_step: "\ \ snd (whileLoop C B r s); C r s \ \ \ snd (B r s)" apply (subst (asm) whileLoop_unroll) apply (clarsimp simp: bind_def condition_def) done lemma snd_whileLoopE_first_step: "\ \ snd (whileLoopE C B r s); C r s \ \ \ snd (B r s)" apply (subgoal_tac "\ \ snd (whileLoopE C B r s); C r s \ \ \ snd ((lift B (Inr r)) s)") apply (clarsimp simp: lift_def) apply (unfold whileLoopE_def) apply (erule snd_whileLoop_first_step) apply clarsimp done lemma snd_whileLoop_unfold: "\ \ snd (whileLoop C B r s); C r s; (r', s') \ fst (B r s) \ \ \ snd (whileLoop C B r' s')" apply (clarsimp simp: whileLoop_def) apply (auto simp: elim: whileLoop_results.cases whileLoop_terminates.cases intro: whileLoop_results.intros whileLoop_terminates.intros) done lemma snd_whileLoopE_unfold: "\ \ snd (whileLoopE C B r s); (Inr r', s') \ fst (B r s); C r s \ \ \ snd (whileLoopE C B r' s')" apply (clarsimp simp: whileLoopE_def) apply (drule snd_whileLoop_unfold) apply clarsimp apply (clarsimp simp: lift_def) apply assumption apply (clarsimp simp: lift_def) done lemma whileLoop_results_cong [cong]: assumes C: "\r s. C r s = C' r s" and B:"\(r :: 'r) (s :: 's). C' r s \ B r s = B' r s" shows "whileLoop_results C B = whileLoop_results C' B'" proof - { fix x y C B C' B' have "\ (x, y) \ whileLoop_results C B; \(r :: 'r) (s :: 's). C r s = C' r s; \r s. C' r s \ B r s = B' r s \ \ (x, y) \ whileLoop_results C' B'" apply (induct rule: whileLoop_results.induct) apply clarsimp apply clarsimp apply (rule whileLoop_results.intros, auto)[1] apply clarsimp apply (rule whileLoop_results.intros, auto)[1] done } thus ?thesis apply - apply (rule set_eqI, rule iffI) apply (clarsimp split: prod.splits) apply (clarsimp simp: C B split: prod.splits) apply (clarsimp split: prod.splits) apply (clarsimp simp: C [symmetric] B [symmetric] split: prod.splits) done qed lemma whileLoop_terminates_cong [cong]: assumes r: "r = r'" and s: "s = s'" and C: "\r s. C r s = C' r s" and B: "\r s. C' r s \ B r s = B' r s" shows "whileLoop_terminates C B r s = whileLoop_terminates C' B' r' s'" proof (rule iffI) assume T: "whileLoop_terminates C B r s" show "whileLoop_terminates C' B' r' s'" apply (insert T r s) apply (induct arbitrary: r' s' rule: whileLoop_terminates.induct) apply (clarsimp simp: C) apply (erule whileLoop_terminates.intros) apply (clarsimp simp: C B split: prod.splits) apply (rule whileLoop_terminates.intros, assumption) apply (clarsimp simp: C B split: prod.splits) done next assume T: "whileLoop_terminates C' B' r' s'" show "whileLoop_terminates C B r s" apply (insert T r s) apply (induct arbitrary: r s rule: whileLoop_terminates.induct) apply (rule whileLoop_terminates.intros) apply (clarsimp simp: C) apply (rule whileLoop_terminates.intros, fastforce simp: C) apply (clarsimp simp: C B split: prod.splits) done qed lemma whileLoop_cong [cong]: "\ \r s. C r s = C' r s; \r s. C r s \ B r s = B' r s \ \ whileLoop C B = whileLoop C' B'" apply (rule ext, clarsimp simp: whileLoop_def) done lemma whileLoopE_cong [cong]: "\ \r s. C r s = C' r s ; \r s. C r s \ B r s = B' r s \ \ whileLoopE C B = whileLoopE C' B'" apply (clarsimp simp: whileLoopE_def) apply (rule whileLoop_cong [THEN arg_cong]) apply (clarsimp split: sum.splits) apply (clarsimp split: sum.splits) apply (clarsimp simp: lift_def throwError_def split: sum.splits) done lemma whileLoop_terminates_wf: "wf {(x, y). C (fst y) (snd y) \ x \ fst (B (fst y) (snd y)) \ whileLoop_terminates C B (fst y) (snd y)}" apply (rule wfI [where A="UNIV" and B="{(r, s). whileLoop_terminates C B r s}"]) apply clarsimp apply clarsimp apply (erule whileLoop_terminates.induct) apply blast apply blast done subsection "Basic induction helper lemmas" lemma whileLoop_results_induct_lemma1: "\ (a, b) \ whileLoop_results C B; b = Some (x, y) \ \ \ C x y" apply (induct rule: whileLoop_results.induct, auto) done lemma whileLoop_results_induct_lemma1': "\ (a, b) \ whileLoop_results C B; a \ b \ \ \x. a = Some x \ C (fst x) (snd x)" apply (induct rule: whileLoop_results.induct, auto) done lemma whileLoop_results_induct_lemma2 [consumes 1]: "\ (a, b) \ whileLoop_results C B; a = Some (x :: 'a \ 'b); b = Some y; P x; \s t. \ P s; t \ fst (B (fst s) (snd s)); C (fst s) (snd s) \ \ P t \ \ P y" apply (induct arbitrary: x y rule: whileLoop_results.induct) apply simp apply simp apply atomize apply fastforce done lemma whileLoop_results_induct_lemma3 [consumes 1]: assumes result: "(Some (r, s), Some (r', s')) \ whileLoop_results C B" and inv_start: "I r s" and inv_step: "\r s r' s'. \ I r s; C r s; (r', s') \ fst (B r s) \ \ I r' s'" shows "I r' s'" apply (rule whileLoop_results_induct_lemma2 [where P="split I" and y="(r', s')" and x="(r, s)", simplified split_def, simplified]) apply (rule result) apply simp apply simp apply fact apply (erule (1) inv_step) apply clarsimp done subsection "Inductive reasoning about whileLoop results" lemma in_whileLoop_induct [consumes 1]: assumes in_whileLoop: "(r', s') \ fst (whileLoop C B r s)" and init_I: "\ r s. \ C r s \ I r s r s" and step: "\r s r' s' r'' s''. \ C r s; (r', s') \ fst (B r s); (r'', s'') \ fst (whileLoop C B r' s'); I r' s' r'' s'' \ \ I r s r'' s''" shows "I r s r' s'" proof cases assume "C r s" { obtain a where a_def: "a = Some (r, s)" by blast obtain b where b_def: "b = Some (r', s')" by blast have "\ (a, b) \ whileLoop_results C B; \x. a = Some x; \x. b = Some x \ \ I (fst (the a)) (snd (the a)) (fst (the b)) (snd (the b))" apply (induct rule: whileLoop_results.induct) apply (auto simp: init_I whileLoop_def intro: step) done hence "(Some (r, s), Some (r', s')) \ whileLoop_results C B \ I r s r' s'" by (clarsimp simp: a_def b_def) } thus ?thesis using in_whileLoop by (clarsimp simp: whileLoop_def) next assume "\ C r s" hence "r' = r \ s' = s" using in_whileLoop by (subst (asm) whileLoop_unroll, clarsimp simp: condition_def return_def) thus ?thesis by (metis init_I `\ C r s`) qed lemma snd_whileLoop_induct [consumes 1]: assumes induct: "snd (whileLoop C B r s)" and terminates: "\ whileLoop_terminates C B r s \ I r s" and init: "\ r s. \ snd (B r s); C r s \ \ I r s" and step: "\r s r' s' r'' s''. \ C r s; (r', s') \ fst (B r s); snd (whileLoop C B r' s'); I r' s' \ \ I r s" shows "I r s" apply (insert init induct) apply atomize apply (unfold whileLoop_def) apply clarsimp apply (erule disjE) apply (erule rev_mp) apply (induct "Some (r, s)" "None :: ('a \ 'b) option" arbitrary: r s rule: whileLoop_results.induct) apply clarsimp apply clarsimp apply (erule (1) step) apply (clarsimp simp: whileLoop_def) apply clarsimp apply (metis terminates) done lemma whileLoop_terminatesE_induct [consumes 1]: assumes induct: "whileLoop_terminatesE C B r s" and init: "\r s. \ C r s \ I r s" and step: "\r s r' s'. \ C r s; \(v', s') \ fst (B r s). case v' of Inl _ \ True | Inr r' \ I r' s' \ \ I r s" shows "I r s" apply (insert induct) apply (clarsimp simp: whileLoop_terminatesE_def) apply (subgoal_tac "(\r s. case (Inr r) of Inl x \ True | Inr x \ I x s) r s") apply simp apply (induction rule: whileLoop_terminates.induct) apply (case_tac r) apply simp apply clarsimp apply (erule init) apply (clarsimp split: sum.splits) apply (rule step) apply simp apply (clarsimp simp: lift_def split: sum.splits) apply force done subsection "Direct reasoning about whileLoop components" lemma fst_whileLoop_cond_false: assumes loop_result: "(r', s') \ fst (whileLoop C B r s)" shows "\ C r' s'" using loop_result by (rule in_whileLoop_induct, auto) lemma snd_whileLoop: assumes init_I: "I r s" and cond_I: "C r s" and non_term: "\r. \ \s. I r s \ C r s \ \ snd (B r s) \ B r \\ \r' s'. C r' s' \ I r' s' \" shows "snd (whileLoop C B r s)" apply (clarsimp simp: whileLoop_def) apply (rotate_tac) apply (insert init_I cond_I) apply (induct rule: whileLoop_terminates.induct) apply clarsimp apply (cut_tac r=r in non_term) apply (clarsimp simp: exs_valid_def) apply (subst (asm) (2) whileLoop_results.simps) apply clarsimp apply (insert whileLoop_results.simps) apply fast done lemma whileLoop_terminates_inv: assumes init_I: "I r s" assumes inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \" assumes wf_R: "wf R" shows "whileLoop_terminates C B r s" apply (insert init_I) using wf_R apply (induction "(r, s)" arbitrary: r s) apply atomize apply (subst whileLoop_terminates_simps) apply clarsimp apply (erule use_valid) apply (rule hoare_strengthen_post, rule inv) apply force apply force done lemma not_snd_whileLoop: assumes init_I: "I r s" and inv_holds: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \!" and wf_R: "wf R" shows "\ snd (whileLoop C B r s)" proof - { fix x y have "\ (x, y) \ whileLoop_results C B; x = Some (r, s); y = None \ \ False" apply (insert init_I) apply (induct arbitrary: r s rule: whileLoop_results.inducts) apply simp apply simp apply (insert snd_validNF [OF inv_holds])[1] apply blast apply (drule use_validNF [OF _ inv_holds]) apply simp apply clarsimp apply blast done } also have "whileLoop_terminates C B r s" apply (rule whileLoop_terminates_inv [where I=I, OF init_I _ wf_R]) apply (insert inv_holds) apply (clarsimp simp: validNF_def) done ultimately show ?thesis by (clarsimp simp: whileLoop_def, blast) qed lemma valid_whileLoop: assumes first_step: "\s. P r s \ I r s" and inv_step: "\r. \ \s. I r s \ C r s \ B r \ I \" and final_step: "\r s. \ I r s; \ C r s \ \ Q r s" shows "\ P r \ whileLoop C B r \ Q \" proof - { fix r' s' s assume inv: "I r s" assume step: "(r', s') \ fst (whileLoop C B r s)" have "I r' s'" using step inv apply (induct rule: in_whileLoop_induct) apply simp apply (drule use_valid, rule inv_step, auto) done } thus ?thesis apply (clarsimp simp: valid_def) apply (drule first_step) apply (rule final_step, simp) apply (metis fst_whileLoop_cond_false) done qed lemma whileLoop_wp: "\ \r. \ \s. I r s \ C r s \ B r \ I \; \r s. \ I r s; \ C r s \ \ Q r s \ \ \ I r \ whileLoop C B r \ Q \" by (rule valid_whileLoop) lemma whileLoop_wp_inv [wp]: "\ \r. \\s. I r s \ C r s\ B r \I\; \r s. \I r s; \ C r s\ \ Q r s \ \ \ I r \ whileLoop_inv C B r I M \ Q \" apply (clarsimp simp: whileLoop_inv_def) apply (rule valid_whileLoop [where P=I and I=I], auto) done lemma validE_whileLoopE: "\\s. P r s \ I r s; \r. \ \s. I r s \ C r s \ B r \ I \,\ A \; \r s. \ I r s; \ C r s \ \ Q r s \ \ \ P r \ whileLoopE C B r \ Q \,\ A \" apply (clarsimp simp: whileLoopE_def validE_def) apply (rule valid_whileLoop [where I="\r s. (case r of Inl x \ A x s | Inr x \ I x s)" and Q="\r s. (case r of Inl x \ A x s | Inr x \ Q x s)"]) apply atomize apply (clarsimp simp: valid_def lift_def split: sum.splits) apply (clarsimp simp: valid_def lift_def split: sum.splits) apply (clarsimp split: sum.splits) done lemma whileLoopE_wp: "\ \r. \ \s. I r s \ C r s \ B r \ I \, \ A \; \r s. \ I r s; \ C r s \ \ Q r s \ \ \ I r \ whileLoopE C B r \ Q \, \ A \" by (rule validE_whileLoopE) lemma exs_valid_whileLoop: assumes init_T: "\s. P s \ T r s" and iter_I: "\ r s0. \ \s. T r s \ C r s \ s = s0 \ B r \\\r' s'. T r' s' \ ((r', s'),(r, s0)) \ R\" and wf_R: "wf R" and final_I: "\r s. \ T r s; \ C r s \ \ Q r s" shows "\ P \ whileLoop C B r \\ Q \" proof (clarsimp simp: exs_valid_def Bex_def) fix s assume "P s" { fix x have "T (fst x) (snd x) \ \r' s'. (r', s') \ fst (whileLoop C B (fst x) (snd x)) \ T r' s'" using wf_R apply induction apply atomize apply (case_tac "C (fst x) (snd x)") apply (subst whileLoop_unroll) apply (clarsimp simp: condition_def bind_def' split: prod.splits) apply (cut_tac ?s0.0=b and r=a in iter_I) apply (clarsimp simp: exs_valid_def) apply blast apply (subst whileLoop_unroll) apply (clarsimp simp: condition_def bind_def' return_def) done } thus "\r' s'. (r', s') \ fst (whileLoop C B r s) \ Q r' s'" by (metis `P s` fst_conv init_T snd_conv final_I fst_whileLoop_cond_false) qed lemma empty_fail_whileLoop: assumes body_empty_fail: "\r. empty_fail (B r)" shows "empty_fail (whileLoop C B r)" proof - { fix s A assume empty: "fst (whileLoop C B r s) = {}" have cond_true: "\x s. fst (whileLoop C B x s) = {} \ C x s" apply (subst (asm) whileLoop_unroll) apply (clarsimp simp: condition_def return_def split: split_if_asm) done have "snd (whileLoop C B r s)" apply (rule snd_whileLoop [where I="\x s. fst (whileLoop C B x s) = {}"]) apply fact apply (rule cond_true, fact) apply (clarsimp simp: exs_valid_def) apply (case_tac "fst (B r s) = {}") apply (metis empty_failD [OF body_empty_fail]) apply (subst (asm) whileLoop_unroll) apply (fastforce simp: condition_def bind_def split_def cond_true) done } thus ?thesis by (clarsimp simp: empty_fail_def) qed lemma empty_fail_whileLoopE: assumes body_empty_fail: "\r. empty_fail (B r)" shows "empty_fail (whileLoopE C B r)" apply (clarsimp simp: whileLoopE_def) apply (rule empty_fail_whileLoop) apply (insert body_empty_fail) apply (clarsimp simp: empty_fail_def lift_def throwError_def return_def split: sum.splits) done lemma whileLoop_results_bisim: assumes base: "(a, b) \ whileLoop_results C B" and vars1: "Q = (case a of Some (r, s) \ Some (rt r, st s) | _ \ None)" and vars2: "R = (case b of Some (r, s) \ Some (rt r, st s) | _ \ None)" and inv_init: "case a of Some (r, s) \ I r s | _ \ True" and inv_step: "\r s r' s'. \ I r s; C r s; (r', s') \ fst (B r s) \ \ I r' s'" and cond_match: "\r s. I r s \ C r s = C' (rt r) (st s)" and fail_step: "\r s. \C r s; snd (B r s); I r s\ \ (Some (rt r, st s), None) \ whileLoop_results C' B'" and refine: "\r s r' s'. \ I r s; C r s; (r', s') \ fst (B r s) \ \ (rt r', st s') \ fst (B' (rt r) (st s))" shows "(Q, R) \ whileLoop_results C' B'" apply (subst vars1) apply (subst vars2) apply (insert base inv_init) apply (induct rule: whileLoop_results.induct) apply clarsimp apply (subst (asm) cond_match) apply (clarsimp simp: option.splits) apply (clarsimp simp: option.splits) apply (clarsimp simp: option.splits) apply (metis fail_step) apply (case_tac z) apply (clarsimp simp: option.splits) apply (metis cond_match inv_step refine whileLoop_results.intros(3)) apply (clarsimp simp: option.splits) apply (metis cond_match inv_step refine whileLoop_results.intros(3)) done lemma whileLoop_terminates_liftE: "whileLoop_terminatesE C (\r. liftE (B r)) r s = whileLoop_terminates C B r s" apply (subst eq_sym_conv) apply (clarsimp simp: whileLoop_terminatesE_def) apply (rule iffI) apply (erule whileLoop_terminates.induct) apply (rule whileLoop_terminates.intros) apply clarsimp apply (clarsimp simp: split_def) apply (rule whileLoop_terminates.intros(2)) apply clarsimp apply (clarsimp simp: liftE_def in_bind return_def lift_def [abs_def] bind_def lift_def throwError_def o_def split: sum.splits cong: sum.case_cong) apply (drule (1) bspec) apply clarsimp apply (subgoal_tac "case (Inr r) of Inl _ \ True | Inr r \ whileLoop_terminates (\r s. (\r s. case r of Inl _ \ False | Inr v \ C v s) (Inr r) s) (\r. (lift (\r. liftE (B r)) (Inr r)) >>= (\x. return (theRight x))) r s") apply (clarsimp simp: liftE_def lift_def) apply (erule whileLoop_terminates.induct) apply (clarsimp simp: liftE_def lift_def split: sum.splits) apply (erule whileLoop_terminates.intros) apply (clarsimp simp: liftE_def split: sum.splits) apply (clarsimp simp: bind_def return_def split_def lift_def) apply (erule whileLoop_terminates.intros) apply force done lemma snd_X_return [simp]: "\A X s. snd ((A >>= (\a. return (X a))) s) = snd (A s)" by (clarsimp simp: return_def bind_def split_def) lemma whileLoopE_liftE: "whileLoopE C (\r. liftE (B r)) r = liftE (whileLoop C B r)" apply (rule ext) apply (clarsimp simp: whileLoopE_def) apply (rule prod_eqI) apply (rule set_eqI, rule iffI) apply clarsimp apply (clarsimp simp: in_bind whileLoop_def liftE_def) apply (rule_tac x="b" in exI) apply (rule_tac x="theRight a" in exI) apply (rule conjI) apply (erule whileLoop_results_bisim [where rt=theRight and st="\x. x" and I="\r s. case r of Inr x \ True | _ \ False"], auto intro: whileLoop_results.intros intro!: bexI simp: bind_def return_def lift_def split: sum.splits)[1] apply (drule whileLoop_results_induct_lemma2 [where P="\(r, s). case r of Inr x \ True | _ \ False"] ) apply (rule refl) apply (rule refl) apply clarsimp apply (clarsimp simp: return_def bind_def lift_def split: sum.splits) apply (clarsimp simp: return_def bind_def lift_def split: sum.splits) apply (clarsimp simp: in_bind whileLoop_def liftE_def) apply (erule whileLoop_results_bisim [where rt=Inr and st="\x. x" and I="\r s. True"], auto intro: whileLoop_results.intros intro!: bexI simp: bind_def return_def lift_def split: sum.splits)[1] apply (rule iffI) apply (clarsimp simp: whileLoop_def liftE_def del: notI) apply (erule disjE) apply (erule whileLoop_results_bisim [where rt=theRight and st="\x. x" and I="\r s. case r of Inr x \ True | _ \ False"], auto intro: whileLoop_results.intros intro!: bexI simp: bind_def return_def lift_def split: sum.splits)[1] apply (subst (asm) whileLoop_terminates_liftE [symmetric]) apply (fastforce simp: whileLoop_def liftE_def whileLoop_terminatesE_def) apply (clarsimp simp: whileLoop_def liftE_def del: notI) apply (subst (asm) whileLoop_terminates_liftE [symmetric]) apply (clarsimp simp: whileLoop_def liftE_def whileLoop_terminatesE_def) apply (erule disjE) apply (erule whileLoop_results_bisim [where rt=Inr and st="\x. x" and I="\r s. True"]) apply (clarsimp split: option.splits) apply (clarsimp split: option.splits) apply (clarsimp split: option.splits) apply (auto intro: whileLoop_results.intros intro!: bexI simp: bind_def return_def lift_def split: sum.splits) done lemma validNF_whileLoop: assumes pre: "\s. P r s \ I r s" and inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \!" and wf: "wf R" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\P r\ whileLoop C B r \Q\!" apply rule apply (rule valid_whileLoop) apply fact apply (insert inv, clarsimp simp: validNF_def valid_def split: prod.splits, force)[1] apply (metis post_cond) apply (unfold no_fail_def) apply (intro allI impI) apply (rule not_snd_whileLoop [where I=I and R=R]) apply (auto intro: assms) done lemma validNF_whileLoop_inv [wp]: assumes inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \!" and wf: "wf R" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoop_inv C B r I R \Q\!" apply (clarsimp simp: whileLoop_inv_def) apply (rule validNF_whileLoop [where I=I and R=R]) apply simp apply (rule inv) apply (rule wf) apply (metis post_cond) done lemma validNF_whileLoop_inv_measure [wp]: assumes inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ M r' s' < M r s \!" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoop_inv C B r I (measure' (\(r, s). M r s)) \Q\!" apply (clarsimp simp: whileLoop_inv_def) apply (rule validNF_whileLoop [where R="measure' (\(r, s). M r s)" and I=I]) apply simp apply clarsimp apply (rule inv) apply simp apply (metis post_cond) done lemma validNF_whileLoop_inv_measure_twosteps: assumes inv: "\r s. \\s'. I r s' \ C r s' \ B r \ \r' s'. I r' s' \!" assumes measure: "\r m. \\s. I r s \ C r s \ M r s = m \ B r \ \r' s'. M r' s' < m \" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoop_inv C B r I (measure' (\(r, s). M r s)) \Q\!" apply (rule validNF_whileLoop_inv_measure) apply (rule validNF_weaken_pre) apply (rule validNF_post_comb_conj_L) apply (rule inv) apply (rule measure) apply fast apply (metis post_cond) done lemma wf_custom_measure: "\ \a b. (a, b) \ R \ f a < (f :: 'a \ nat) b \ \ wf R" by (metis in_measure wf_def wf_measure) lemma validNF_whileLoopE: assumes pre: "\s. P r s \ I r s" and inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \,\ E \!" and wf: "wf R" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\ P r \ whileLoopE C B r \ Q \,\ E \!" apply (unfold validE_NF_alt_def whileLoopE_def) apply (rule validNF_whileLoop [ where I="\r s. case r of Inl x \ E x s | Inr x \ I x s" and R="{((r', s'), (r, s)). \x x'. r' = Inl x' \ r = Inr x} \ {((r', s'), (r, s)). \x x'. r' = Inr x' \ r = Inr x \ ((x', s'),(x, s)) \ R}"]) apply (simp add: pre) apply (insert inv)[1] apply (fastforce simp: lift_def validNF_def valid_def validE_NF_def throwError_def no_fail_def return_def validE_def split: sum.splits prod.splits) apply (rule wf_Un) apply (rule wf_custom_measure [where f="\(r, s). case r of Inl _ \ 0 | _ \ 1"]) apply clarsimp apply (insert wf_inv_image [OF wf, where f="\(r, s). (theRight r, s)"]) apply (drule wf_Int1 [where r'="{((r', s'),(r, s)). (\x. r = Inr x) \ (\x. r' = Inr x)}"]) apply (erule wf_subset) apply rule apply (clarsimp simp: inv_image_def split: prod.splits sum.splits) apply clarsimp apply rule apply rule apply clarsimp apply clarsimp apply (clarsimp split: sum.splits) apply (metis post_cond) done lemma validNF_whileLoopE_inv [wp]: assumes inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ ((r', s'), (r, s)) \ R \,\ E \!" and wf_R: "wf R" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoopE_inv C B r I R \Q\,\E\!" apply (clarsimp simp: whileLoopE_inv_def) apply (metis validNF_whileLoopE [OF _ inv] post_cond wf_R) done lemma validNF_whileLoopE_inv_measure [wp]: assumes inv: "\r s. \\s'. I r s' \ C r s' \ s' = s \ B r \ \r' s'. I r' s' \ M r' s' < M r s \, \ E \!" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoopE_inv C B r I (measure' (\(r, s). M r s)) \Q\,\E\!" apply (rule validNF_whileLoopE_inv) apply clarsimp apply (rule inv) apply clarsimp apply (metis post_cond) done lemma validNF_whileLoopE_inv_measure_twosteps: assumes inv: "\r s. \\s'. I r s' \ C r s' \ B r \ \r' s'. I r' s' \, \ E \!" assumes measure: "\r m. \\s. I r s \ C r s \ M r s = m \ B r \ \r' s'. M r' s' < m \, \ \_ _. True \" and post_cond: "\r s. \I r s; \ C r s\ \ Q r s" shows "\I r\ whileLoopE_inv C B r I (measure' (\(r, s). M r s)) \Q\, \E\!" apply (rule validNF_whileLoopE_inv_measure) apply (rule validE_NF_weaken_pre) apply (rule validE_NF_post_comb_conj_L) apply (rule inv) apply (rule measure) apply fast apply (metis post_cond) done lemma whileLoopE_wp_inv [wp]: "\ \r. \\s. I r s \ C r s\ B r \I\,\E\; \r s. \I r s; \ C r s\ \ Q r s \ \ \ I r \ whileLoopE_inv C B r I M \ Q \,\ E \" apply (clarsimp simp: whileLoopE_inv_def) apply (rule validE_whileLoopE [where I=I], auto) done subsection "Stronger whileLoop rules" lemma whileLoop_rule_strong: assumes init_U: "\ \s'. s' = s \ whileLoop C B r \ \r s. (r, s) \ fst Q \" and path_exists: "\r'' s''. \ (r'', s'') \ fst Q \ \ \ \s'. s' = s \ whileLoop C B r \\ \r s. r = r'' \ s = s'' \" and loop_fail: "snd Q \ snd (whileLoop C B r s)" and loop_nofail: "\ snd Q \ \ \s'. s' = s \ whileLoop C B r \ \_ _. True \!" shows "whileLoop C B r s = Q" using assms apply atomize apply (clarsimp simp: valid_def exs_valid_def validNF_def no_fail_def) apply rule apply blast apply blast apply blast done lemma whileLoop_rule_strong_no_fail: assumes init_U: "\ \s'. s' = s \ whileLoop C B r \ \r s. (r, s) \ fst Q \!" and path_exists: "\r'' s''. \ (r'', s'') \ fst Q \ \ \ \s'. s' = s \ whileLoop C B r \\ \r s. r = r'' \ s = s'' \" and loop_no_fail: "\ snd Q" shows "whileLoop C B r s = Q" apply (rule whileLoop_rule_strong) apply (metis init_U validNF_valid) apply (metis path_exists) apply (metis loop_no_fail) apply (metis (lifting, no_types) init_U validNF_chain) done subsection "Miscellaneous rules" (* Failure of one whileLoop implies the failure of another whileloop * which will only ever fail more. *) lemma snd_whileLoop_subset: assumes a_fails: "snd (whileLoop C A r s)" and b_success_step: "\r s r' s'. \ C r s; (r', s') \ fst (A r s); \ snd (B r s) \ \ (r', s') \ fst (B r s)" and b_fail_step: "\r s. \ C r s; snd (A r s) \ \ snd (B r s) " shows "snd (whileLoop C B r s)" apply (insert a_fails) apply (induct rule: snd_whileLoop_induct) apply (unfold whileLoop_def snd_conv)[1] apply (rule disjCI, simp) apply rotate_tac apply (induct rule: whileLoop_terminates.induct) apply (subst (asm) whileLoop_terminates.simps) apply simp apply (subst (asm) (3) whileLoop_terminates.simps, clarsimp) apply (subst whileLoop_results.simps, clarsimp) apply (rule classical) apply (frule b_success_step, assumption, simp) apply (drule (1) bspec) apply clarsimp apply (frule (1) b_fail_step) apply (metis snd_whileLoop_first_step) apply (metis b_success_step snd_whileLoop_first_step snd_whileLoop_unfold) done end