diff --git a/thys/VerifyThis2019/Parallel_Multiset_Fold.thy b/thys/VerifyThis2019/Parallel_Multiset_Fold.thy --- a/thys/VerifyThis2019/Parallel_Multiset_Fold.thy +++ b/thys/VerifyThis2019/Parallel_Multiset_Fold.thy @@ -1,236 +1,236 @@ section \Iterating a Commutative Computation Concurrently\ theory Parallel_Multiset_Fold imports "HOL-Library.Multiset" begin text \ This theory formalizes a deep embedding of a simple parallel computation model. In this model, we formalize a computation scheme to execute a fold-function over a commutative operation concurrently, and prove it correct. \ subsection \Misc\ (* TODO: Move *) lemma (in comp_fun_commute) fold_mset_rewr: "fold_mset f a (mset l) = fold f l a" by (induction l arbitrary: a; clarsimp; metis fold_mset_fun_left_comm) lemma finite_set_of_finite_maps: fixes A :: "'a set" and B :: "'b set" assumes "finite A" and "finite B" shows "finite {m. dom m \ A \ ran m \ B}" proof - have "{m. dom m \ A \ ran m \ B} \ (\ S \ {S. S \ A}. {m. dom m = S \ ran m \ B})" by auto moreover have "finite \" using assms by (auto intro!: finite_set_of_finite_maps intro: finite_subset) ultimately show ?thesis by (rule finite_subset) qed lemma wf_rtranclp_ev_induct[consumes 1, case_names step]: assumes "wf {(x, y). R y x}" and step: "\ x. R\<^sup>*\<^sup>* a x \ P x \ (\ y. R x y)" shows "\x. P x \ R\<^sup>*\<^sup>* a x" proof - have "\y. P y \ R\<^sup>*\<^sup>* x y" if "R\<^sup>*\<^sup>* a x" for x using assms(1) that proof induction case (less x) from step[OF \R\<^sup>*\<^sup>* a x\] have "P x \ (\y. R x y)" . then show ?case proof assume "P x" then show ?case by auto next assume "\y. R x y" then obtain y where "R x y" .. with less(1)[of y] less(2) show ?thesis by simp (meson converse_rtranclp_into_rtranclp rtranclp.rtrancl_into_rtrancl) qed qed then show ?thesis by blast qed subsection \The Concurrent System\ text \ A state of our concurrent systems consists of a list of tasks, a partial map from threads to the task they are currently working on, and the current computation result.\ type_synonym ('a, 's) state = "'a list \ (nat \ 'a) \ 's" context comp_fun_commute begin context fixes n :: nat \ \The number of threads.\ assumes n_gt_0[simp, intro]: "n > 0" begin text \ A state is \<^emph>\final\ if there are no remaining tasks and if all workers have finished their work.\ definition "final \ \(ts, ws, r). ts = [] \ dom ws \ {0..At any point a thread can: \<^item> pick a new task from the queue if it is currently not busy \<^item> or execute its current task.\ inductive step :: "('a, 'b) state \ ('a, 'b) state \ bool" where pick: "step (t # ts, ws, s) (ts, ws(i := Some t), s)" if "ws i = None" and "i < n" | exec: "step (ts, ws, s) (ts, ws(i := None), f a s)" if "ws i = Some a" and "i < n" lemma no_deadlock: assumes "\ final cfg" shows "\cfg'. step cfg cfg'" using assms apply (cases cfg) apply safe subgoal for ts ws s by (cases ts; cases "ws 0") (auto 4 5 simp: final_def intro: step.intros) done lemma wf_step: "wf {((ts', ws', r'), (ts, ws, r)). step (ts, ws, r) (ts', ws', r') \ set ts' \ S \ dom ws \ {0.. ran ws \ S}" if "finite S" proof - let ?R1 = "{(x, y). dom x \ dom y \ ran x \ S \ dom y \ {0.. ran y \ S}" have "?R1 \ {y. dom y \ {0.. ran y \ S} \ {y. dom y \ {0.. ran y \ S}" by auto then have "finite ?R1" using \finite S\ by - (erule finite_subset, auto intro: finite_set_of_finite_maps) then have [intro]: "wf ?R1" apply (rule finite_acyclic_wf) - apply (rule order_class.acyclicI_order[where f = "\x. n - card (dom x)"]) + apply (rule preorder_class.acyclicI_order[where f = "\x. n - card (dom x)"]) apply clarsimp by (metis (full_types) cancel_ab_semigroup_add_class.diff_right_commute diff_diff_cancel domD domI psubsetI psubset_card_mono subset_eq_atLeast0_lessThan_card subset_eq_atLeast0_lessThan_finite zero_less_diff) let ?R = "measure length <*lex*> ?R1 <*lex*> {}" have "wf ?R" by auto then show ?thesis apply (rule wf_subset) apply clarsimp apply (erule step.cases; clarsimp) by (smt Diff_iff domIff fun_upd_apply mem_Collect_eq option.simps(3) psubsetI ran_def singletonI subset_iff) qed context fixes ts :: "'a list" and start :: "'b" begin definition "s\<^sub>0 = (ts, \_. None, start)" definition "reachable \ (step\<^sup>*\<^sup>*) s\<^sub>0" lemma reachable0[simp]: "reachable s\<^sub>0" unfolding reachable_def by auto definition "is_invar I \ I s\<^sub>0 \ (\s s'. reachable s \ I s \ step s s' \ I s')" lemma is_invarI[intro?]: "\ I s\<^sub>0; \s s'. \ reachable s; I s; step s s'\ \ I s' \ \ is_invar I" by (auto simp: is_invar_def) lemma invar_reachable: "is_invar I \ reachable s \ I s" unfolding reachable_def by rotate_tac (induction rule: rtranclp_induct, auto simp: is_invar_def reachable_def) definition "invar \ \(ts2, ws, r). (\ts1. mset ts = ts1 + {# the (ws i). i \# mset_set (dom ws \ {0.. r = fold_mset f start ts1 \ set ts2 \ set ts \ ran ws \ set ts \ dom ws \ {0..0_def unfolding invar_def by simp subgoal unfolding invar_def apply (elim step.cases) apply (clarsimp split: option.split_asm) subgoal for ws i t ts ts1 apply (rule exI[where x = ts1]) apply (subst mset_set.insert) apply (auto intro!: multiset.map_cong0) done apply (clarsimp split!: prod.splits) subgoal for ws i a ts ts1 apply (rule exI[where x = "add_mset a ts1"]) apply (subst Diff_Int_distrib2) apply (subst mset_set.remove) apply (auto intro!: multiset.map_cong0 split: if_split_asm simp: ran_def) done done done lemma final_state_correct1: assumes "invar (ts', ms, r)" "final (ts', ms, r)" shows "r = fold_mset f start (mset ts)" using assms unfolding invar_def final_def by auto lemma final_state_correct2: assumes "reachable (ts', ms, r)" "final (ts', ms, r)" shows "r = fold_mset f start (mset ts)" using assms by - (rule final_state_correct1, rule invar_reachable[OF invariant]) text \Soundness: whenever we reach a final state, the computation result is correct.\ theorem final_state_correct: assumes "reachable (ts', ms, r)" "final (ts', ms, r)" shows "r = fold f ts start" using final_state_correct2[OF assms] by (simp add: fold_mset_rewr) text \Termination: at any point during the program execution, we can continue to a final state. That is, the computation always terminates. \ theorem "termination": assumes "reachable s" shows "\s'. final s' \ step\<^sup>*\<^sup>* s s'" proof - have "{(s', s). step s s' \ reachable s} \ {(s', s). step s s' \ reachable s \ reachable s'}" unfolding reachable_def by auto also have "\ \ {((ts', ws', r'), (ts1, ws, r)). step (ts1, ws, r) (ts', ws', r') \ set ts' \ set ts \ dom ws \ {0.. ran ws \ set ts}" by (force dest!: invar_reachable[OF invariant] simp: invar_def) finally have "wf {(s', s). step s s' \ reachable s}" by (elim wf_subset[OF wf_step, rotated]) simp then have "\s'. final s' \ (\s s'. step s s' \ reachable s)\<^sup>*\<^sup>* s s'" proof (induction rule: wf_rtranclp_ev_induct) case (step x) then have "(\s s'. step s s')\<^sup>*\<^sup>* s x" by (elim mono_rtranclp[rule_format, rotated] conjE) with \reachable s\ have "reachable x" unfolding reachable_def by auto then show ?case using no_deadlock[of x] by auto qed then show ?thesis apply clarsimp apply (intro exI conjI, assumption) apply (rule mono_rtranclp[rule_format]) apply auto done qed end (* Fixed task list *) end (* Fixed number of workers *) end (* Commutative function *) text \The main theorems outside the locale:\ thm comp_fun_commute.final_state_correct comp_fun_commute.termination end (* End of theory *) \ No newline at end of file diff --git a/thys/VerifyThis2019/lib/Exc_Nres_Monad.thy b/thys/VerifyThis2019/lib/Exc_Nres_Monad.thy --- a/thys/VerifyThis2019/lib/Exc_Nres_Monad.thy +++ b/thys/VerifyThis2019/lib/Exc_Nres_Monad.thy @@ -1,759 +1,759 @@ section \Exception Monad for Refine-Monadic\ theory Exc_Nres_Monad imports "Refine_Imperative_HOL.IICF" begin (* TODO: * Integrate with sepref --- currently, it's "integrated" by providing some support to translate the program in to a plain nres monad before sepref is invoked. * Move to Refine_Monadic. *) declare TrueI[refine_vcg] type_synonym ('e,'a) enres = "('e + 'a) nres" named_theorems enres_unfolds \Unfolding theorems from enres to nres\ definition [enres_unfolds]: "ERETURN x \ RETURN (Inr x)" definition ebind :: "('e,'a) enres \ ('a \ ('e,'b) enres) \ ('e,'b) enres" where [enres_unfolds]: "ebind m f \ do { x \ m; case x of Inl e \ RETURN (Inl e) | Inr x \ f x }" definition [enres_unfolds]: "THROW e == RETURN (Inl e)" definition [enres_unfolds]: "ESPEC \ \ \ SPEC (\Inl e \ \ e | Inr r \ \ r)" definition [enres_unfolds]: "CATCH m h \ do { r\m; case r of Inl e \ h e | Inr r \ RETURN (Inr r) }" abbreviation (do_notation) bind_doE where "bind_doE \ ebind" -notation (output) bind_doE (infixr "\" 54) -notation (ASCII output) bind_doE (infixr ">>=" 54) +notation (output) bind_doE (infixl "\" 54) +notation (ASCII output) bind_doE (infixl ">>=" 54) nonterminal doE_binds and doE_bind syntax "_doE_block" :: "doE_binds \ 'a" ("doE {//(2 _)//}" [12] 62) "_doE_bind" :: "[pttrn, 'a] \ doE_bind" ("(2_ \/ _)" 13) "_doE_let" :: "[pttrn, 'a] \ doE_bind" ("(2let _ =/ _)" [1000, 13] 13) "_doE_then" :: "'a \ doE_bind" ("_" [14] 13) "_doE_final" :: "'a \ doE_binds" ("_") "_doE_cons" :: "[doE_bind, doE_binds] \ doE_binds" ("_;//_" [13, 12] 12) - "_thenM" :: "['a, 'b] \ 'c" (infixr "\" 54) + "_thenM" :: "['a, 'b] \ 'c" (infixl "\" 54) syntax (ASCII) "_doE_bind" :: "[pttrn, 'a] \ doE_bind" ("(2_ <-/ _)" 13) "_thenM" :: "['a, 'b] \ 'c" (infixr ">>" 54) translations "_doE_block (_doE_cons (_doE_then t) (_doE_final e))" \ "CONST bind_doE t (\_. e)" "_doE_block (_doE_cons (_doE_bind p t) (_doE_final e))" \ "CONST bind_doE t (\p. e)" "_doE_block (_doE_cons (_doE_let p t) bs)" \ "let p = t in _doE_block bs" "_doE_block (_doE_cons b (_doE_cons c cs))" \ "_doE_block (_doE_cons b (_doE_final (_doE_block (_doE_cons c cs))))" "_doE_cons (_doE_let p t) (_doE_final s)" \ "_doE_final (let p = t in s)" "_doE_block (_doE_final e)" \ "e" "(m \ n)" \ "(m \ (\_. n))" definition [enres_unfolds]: "CHECK \ e \ if \ then ERETURN () else THROW e" definition [enres_unfolds]: "EASSUME \ \ if \ then ERETURN () else SUCCEED" definition [enres_unfolds]: "EASSERT \ \ if \ then ERETURN () else FAIL" lemma EASSUME_simps[simp]: "EASSUME True = ERETURN ()" "EASSUME False = SUCCEED" unfolding EASSUME_def by auto lemma EASSERT_simps[simp]: "EASSERT True = ERETURN ()" "EASSERT False = FAIL" unfolding EASSERT_def by auto lemma CHECK_simps[simp]: "CHECK True e = ERETURN ()" "CHECK False e = THROW e" unfolding CHECK_def by auto lemma pw_ESPEC[simp, refine_pw_simps]: "nofail (ESPEC \ \)" "inres (ESPEC \ \) (Inl e) \ \ e" "inres (ESPEC \ \) (Inr x) \ \ x" unfolding enres_unfolds by auto lemma pw_ERETURN[simp, refine_pw_simps]: "nofail (ERETURN x)" "\inres (ERETURN x) (Inl e)" "inres (ERETURN x) (Inr y) \ x=y" unfolding enres_unfolds by auto lemma pw_ebind[refine_pw_simps]: "nofail (ebind m f) \ nofail m \ (\x. inres m (Inr x) \ nofail (f x))" "inres (ebind m f) (Inl e) \ inres m (Inl e) \ (\x. inres m (Inr x) \ inres (f x) (Inl e))" "inres (ebind m f) (Inr x) \ nofail m \ (\y. inres m (Inr y) \ inres (f y) (Inr x))" unfolding enres_unfolds apply (auto simp: refine_pw_simps split: sum.split) using sum.exhaust_sel apply blast using sum.exhaust_sel apply blast done lemma pw_THROW[simp,refine_pw_simps]: "nofail (THROW e)" "inres (THROW e) (Inl f) \ f=e" "\inres (THROW e) (Inr x)" unfolding enres_unfolds by (auto simp: refine_pw_simps) lemma pw_CHECK[simp, refine_pw_simps]: "nofail (CHECK \ e)" "inres (CHECK \ e) (Inl f) \ \\ \ f=e" "inres (CHECK \ e) (Inr u) \ \" unfolding enres_unfolds by (auto simp: refine_pw_simps) lemma pw_EASSUME[simp, refine_pw_simps]: "nofail (EASSUME \)" "\inres (EASSUME \) (Inl e)" "inres (EASSUME \) (Inr u) \ \" unfolding EASSUME_def by (auto simp: refine_pw_simps) lemma pw_EASSERT[simp, refine_pw_simps]: "nofail (EASSERT \) \ \" "inres (EASSERT \) (Inr u)" "inres (EASSERT \) (Inl e) \ \\" unfolding EASSERT_def by (auto simp: refine_pw_simps) lemma pw_CATCH[refine_pw_simps]: "nofail (CATCH m h) \ (nofail m \ (\x. inres m (Inl x) \ nofail (h x)))" "inres (CATCH m h) (Inl e) \ (nofail m \ (\e'. inres m (Inl e') \ inres (h e') (Inl e)))" "inres (CATCH m h) (Inr x) \ inres m (Inr x) \ (\e. inres m (Inl e) \ inres (h e) (Inr x))" unfolding CATCH_def apply (auto simp add: refine_pw_simps split: sum.splits) using sum.exhaust_sel apply blast using sum.exhaust_sel apply blast done lemma pw_ele_iff: "m \ n \ (nofail n \ nofail m \ (\e. inres m (Inl e) \ inres n (Inl e)) \ (\x. inres m (Inr x) \ inres n (Inr x)) )" apply (auto simp: pw_le_iff) by (metis sum.exhaust_sel) lemma pw_eeq_iff: "m = n \ (nofail m \ nofail n) \ (\e. inres m (Inl e) \ inres n (Inl e)) \ (\x. inres m (Inr x) \ inres n (Inr x))" apply (auto simp: pw_eq_iff) by (metis sum.exhaust_sel)+ lemma enres_monad_laws[simp]: "ebind (ERETURN x) f = f x" "ebind m (ERETURN) = m" "ebind (ebind m f) g = ebind m (\x. ebind (f x) g)" by (auto simp: pw_eeq_iff refine_pw_simps) lemma enres_additional_laws[simp]: "ebind (THROW e) f = THROW e" "CATCH (THROW e) h = h e" "CATCH (ERETURN x) h = ERETURN x" "CATCH m THROW = m" apply (auto simp: pw_eeq_iff refine_pw_simps) done lemmas ESPEC_trans = order_trans[where z="ESPEC Error_Postcond Normal_Postcond" for Error_Postcond Normal_Postcond, zero_var_indexes] lemma ESPEC_cons: assumes "m \ ESPEC E Q" assumes "\e. E e \ E' e" assumes "\x. Q x \ Q' x" shows "m \ ESPEC E' Q'" using assms by (auto simp: pw_ele_iff) lemma ebind_rule_iff: "doE { x\m; f x } \ ESPEC \ \ \ m \ ESPEC \ (\x. f x \ ESPEC \ \)" by (auto simp: pw_ele_iff refine_pw_simps) lemmas ebind_rule[refine_vcg] = ebind_rule_iff[THEN iffD2] lemma ERETURN_rule_iff[simp]: "ERETURN x \ ESPEC \ \ \ \ x" by (auto simp: pw_ele_iff refine_pw_simps) lemmas ERETURN_rule[refine_vcg] = ERETURN_rule_iff[THEN iffD2] lemma ESPEC_rule_iff: "ESPEC \ \ \ ESPEC \' \' \ (\e. \ e \ \' e) \ (\x. \ x \ \' x)" by (auto simp: pw_ele_iff refine_pw_simps) lemmas ESPEC_rule[refine_vcg] = ESPEC_rule_iff[THEN iffD2] lemma THROW_rule_iff: "THROW e \ ESPEC \ \ \ \ e" by (auto simp: pw_ele_iff refine_pw_simps) lemmas THROW_rule[refine_vcg] = THROW_rule_iff[THEN iffD2] lemma CATCH_rule_iff: "CATCH m h \ ESPEC \ \ \ m \ ESPEC (\e. h e \ ESPEC \ \) \" by (auto simp: pw_ele_iff refine_pw_simps) lemmas CATCH_rule[refine_vcg] = CATCH_rule_iff[THEN iffD2] lemma CHECK_rule_iff: "CHECK c e \ ESPEC \ \ \ (c \ \ ()) \ (\c \ \ e)" by (auto simp: pw_ele_iff refine_pw_simps) lemma CHECK_rule[refine_vcg]: assumes "c \ \ ()" assumes "\c \ \ e" shows "CHECK c e \ ESPEC \ \" using assms by (simp add: CHECK_rule_iff) lemma EASSUME_rule[refine_vcg]: "\\ \ \ ()\ \ EASSUME \ \ ESPEC E \" by (cases \) auto lemma EASSERT_rule[refine_vcg]: "\\; \ \ \ ()\ \ EASSERT \ \ ESPEC E \" by auto lemma eprod_rule[refine_vcg]: "\\a b. p=(a,b) \ S a b \ ESPEC \ \\ \ (case p of (a,b) \ S a b) \ ESPEC \ \" by (auto split: prod.split) (* TODO: Add a simplifier setup that normalizes nested case-expressions to the vcg! *) lemma eprod2_rule[refine_vcg]: assumes "\a b c d. \ab=(a,b); cd=(c,d)\ \ f a b c d \ ESPEC \ \" shows "(\(a,b) (c,d). f a b c d) ab cd \ ESPEC \ \" using assms by (auto split: prod.split) lemma eif_rule[refine_vcg]: "\ b \ S1 \ ESPEC \ \; \b \ S2 \ ESPEC \ \\ \ (if b then S1 else S2) \ ESPEC \ \" by (auto) lemma eoption_rule[refine_vcg]: "\ v=None \ S1 \ ESPEC \ \; \x. v=Some x \ f2 x \ ESPEC \ \\ \ case_option S1 f2 v \ ESPEC \ \" by (auto split: option.split) lemma eLet_rule[refine_vcg]: "f v \ ESPEC \ \ \ (let x=v in f x) \ ESPEC \ \" by simp lemma eLet_rule': assumes "\x. x=v \ f x \ ESPEC \ \" shows "Let v (\x. f x) \ ESPEC \ \" using assms by simp definition [enres_unfolds]: "EWHILEIT I c f s \ WHILEIT (\Inl _ \ True | Inr s \ I s) (\Inl _ \ False | Inr s \ c s) (\s. ASSERT (\isl s) \ (let s = projr s in f s)) (Inr s)" definition [enres_unfolds]: "EWHILET \ EWHILEIT (\_. True)" lemma EWHILEIT_rule[refine_vcg]: assumes WF: "wf R" and I0: "I s\<^sub>0" and IS: "\s. \I s; b s; (s,s\<^sub>0)\R\<^sup>*\ \ f s \ ESPEC E (\s'. I s' \ (s', s) \ R)" and IMP: "\s. \I s; \ b s; (s,s\<^sub>0)\R\<^sup>*\ \ \ s" shows "EWHILEIT I b f s\<^sub>0 \ ESPEC E \" unfolding EWHILEIT_def ESPEC_def apply (rule order_trans[OF WHILEIT_weaken[where I="\Inl e \ E e | Inr s \ I s \ (s,s\<^sub>0)\R\<^sup>*"]]) apply (auto split: sum.splits) [] apply (rule WHILEIT_rule[where R="inv_image (less_than <*lex*> R) (\Inl e \ (0,undefined) | Inr s \ (1,s))"]) subgoal using WF by auto subgoal using I0 by auto subgoal apply (clarsimp split: sum.splits simp: ESPEC_def) apply (rule order_trans[OF IS]) apply (auto simp: ESPEC_def) done subgoal using IMP by (auto split: sum.splits) done lemma EWHILET_rule: assumes WF: "wf R" and I0: "I s\<^sub>0" and IS: "\s. \I s; b s; (s,s\<^sub>0)\R\<^sup>*\ \ f s \ ESPEC E (\s'. I s' \ (s', s) \ R)" and IMP: "\s. \I s; \ b s; (s,s\<^sub>0)\R\<^sup>*\ \ \ s" shows "EWHILET b f s\<^sub>0 \ ESPEC E \" unfolding EWHILET_def EWHILEIT_def ESPEC_def apply (rule order_trans[OF WHILEIT_weaken[where I="\Inl e \ E e | Inr s \ I s \ (s,s\<^sub>0)\R\<^sup>*"]]) apply (auto split: sum.splits) [] apply (rule WHILEIT_rule[where R="inv_image (less_than <*lex*> R) (\Inl e \ (0,undefined) | Inr s \ (1,s))"]) subgoal using WF by auto subgoal using I0 by auto subgoal apply (clarsimp split: sum.splits simp: ESPEC_def) apply (rule order_trans[OF IS]) apply (auto simp: ESPEC_def) done subgoal using IMP by (auto split: sum.splits) done lemma EWHILEIT_weaken: assumes "\x. I x \ I' x" shows "EWHILEIT I' b f x \ EWHILEIT I b f x" unfolding enres_unfolds apply (rule WHILEIT_weaken) using assms by (auto split: sum.split) text \Explicitly specify a different invariant. \ lemma EWHILEIT_expinv_rule: assumes WF: "wf R" and I0: "I s\<^sub>0" and IS: "\s. \I s; b s; (s,s\<^sub>0)\R\<^sup>*\ \ f s \ ESPEC E (\s'. I s' \ (s', s) \ R)" and IMP: "\s. \I s; \ b s; (s,s\<^sub>0)\R\<^sup>*\ \ \ s" and INVIMP: "\s. I s \ I' s" shows "EWHILEIT I' b f s\<^sub>0 \ ESPEC E \" apply (rule order_trans[OF EWHILEIT_weaken]) using INVIMP apply assumption apply (rule EWHILEIT_rule; fact+) done definition [enres_unfolds]: "enfoldli l c f s \ nfoldli l (\Inl e\False | Inr x \ c x) (\x s. do {ASSERT (\isl s); let s=projr s; f x s}) (Inr s)" lemma enfoldli_simps[simp]: "enfoldli [] c f s = ERETURN s" "enfoldli (x#ls) c f s = (if c s then doE { s\f x s; enfoldli ls c f s} else ERETURN s)" unfolding enres_unfolds by (auto split: sum.split intro!: arg_cong[where f = "Refine_Basic.bind _"] ext) lemma enfoldli_rule: assumes I0: "I [] l0 \0" assumes IS: "\x l1 l2 \. \ l0=l1@x#l2; I l1 (x#l2) \; c \ \ \ f x \ \ ESPEC E (I (l1@[x]) l2)" assumes FNC: "\l1 l2 \. \ l0=l1@l2; I l1 l2 \; \c \ \ \ P \" assumes FC: "\\. \ I l0 [] \; c \ \ \ P \" shows "enfoldli l0 c f \0 \ ESPEC E P" unfolding enfoldli_def ESPEC_def apply (rule nfoldli_rule[where I="\l1 l2. \Inl e \ E e | Inr \ \ I l1 l2 \"]) subgoal by (auto simp: I0) subgoal apply (simp split: sum.splits) apply (erule (2) order_trans[OF IS]) apply (auto simp: ESPEC_def) done subgoal using FNC by (auto split: sum.split) subgoal using FC by (auto split: sum.split) done subsection \Data Refinement\ lemma sum_rel_conv: "(Inl l, s') \ \L,R\sum_rel \ (\l'. s'=Inl l' \ (l,l')\L)" "(Inr r, s') \ \L,R\sum_rel \ (\r'. s'=Inr r' \ (r,r')\R)" "(s, Inl l') \ \L,R\sum_rel \ (\l. s=Inl l \ (l,l')\L)" "(s, Inr r') \ \L,R\sum_rel \ (\r. s=Inr r \ (r,r')\R)" "(\l. s \ Inl l) \ (\r. s=Inr r)" "(\r. s \ Inr r) \ (\l. s=Inl l)" apply - subgoal by (cases s'; auto) subgoal by (cases s'; auto) subgoal by (cases s; auto) subgoal by (cases s; auto) subgoal by (cases s; auto) subgoal by (cases s; auto) done definition econc_fun ("\\<^sub>E") where [enres_unfolds]: "econc_fun E R \ \(\E,R\sum_rel)" lemma RELATES_pat_erefine[refine_dref_pattern]: "\RELATES R; mi \\\<^sub>E E R m \ \ mi \\\<^sub>E E R m" . lemma pw_econc_iff[refine_pw_simps]: "inres (\\<^sub>E E R m) (Inl ei) \ (nofail m \ (\e. inres m (Inl e) \ (ei,e)\E))" "inres (\\<^sub>E E R m) (Inr xi) \ (nofail m \ (\x. inres m (Inr x) \ (xi,x)\R))" "nofail (\\<^sub>E E R m) \ nofail m" by (auto simp: refine_pw_simps econc_fun_def sum_rel_conv) lemma econc_fun_id[simp]: "\\<^sub>E Id Id = (\x. x)" by (auto simp: pw_eeq_iff refine_pw_simps intro!: ext) lemma econc_fun_ESPEC: "\\<^sub>E E R (ESPEC \ \) = ESPEC (\ei. \e. (ei,e)\E \ \ e) (\ri. \r. (ri,r)\R \ \ r)" by (auto simp: pw_eeq_iff refine_pw_simps) lemma econc_fun_ERETURN: "\\<^sub>E E R (ERETURN x) = ESPEC (\_. False) (\xi. (xi,x)\R)" by (auto simp: pw_eeq_iff refine_pw_simps) lemma econc_fun_univ_id[simp]: "\\<^sub>E UNIV Id (ESPEC \ \) = ESPEC (\_. Ex \) \" by (auto simp: pw_eeq_iff refine_pw_simps) lemma erefine_same_sup_Id[simp]: "\ Id\E; Id\R \ \ m \\\<^sub>E E R m" by (auto simp: pw_ele_iff refine_pw_simps) lemma econc_mono3: "m\m' \ \\<^sub>E E R m \ \\<^sub>E E R m'" by (auto simp: pw_ele_iff refine_pw_simps) (* Order of these two is important! *) lemma econc_x_trans[trans]: "x \ \\<^sub>E E R y \ y \ z \ x \ \\<^sub>E E R z" by (force simp: pw_ele_iff refine_pw_simps) lemma econc_econc_trans[trans]: "x \\\<^sub>E E1 R1 y \ y \ \\<^sub>E E2 R2 z \ x \ \\<^sub>E (E1 O E2) (R1 O R2) z" by (force simp: pw_ele_iff refine_pw_simps) lemma ERETURN_refine[refine]: assumes "(xi,x)\R" shows "ERETURN xi \ \\<^sub>EE R (ERETURN x)" using assms by (auto simp: pw_ele_iff refine_pw_simps) lemma EASSERT_bind_refine_right: assumes "\ \ mi \\\<^sub>E E R m" shows "mi \\\<^sub>E E R (doE {EASSERT \; m})" using assms by (simp add: pw_ele_iff refine_pw_simps) lemma EASSERT_bind_refine_left: assumes "\" assumes "mi \\\<^sub>E E R m" shows "(doE {EASSERT \; mi}) \\\<^sub>E E R m" using assms by simp lemma EASSUME_bind_refine_right: assumes "\" assumes "mi \\\<^sub>E E R m" shows "mi \\\<^sub>E E R (doE {EASSUME \; m})" using assms by (simp) lemma EASSUME_bind_refine_left: assumes "\ \ mi \\\<^sub>E E R m" shows "(doE {EASSUME \; mi}) \\\<^sub>E E R m" using assms by (simp add: pw_ele_iff refine_pw_simps) lemma ebind_refine: assumes "mi \\\<^sub>E E R' m" assumes "\xi x. (xi,x)\R' \ fi xi \\\<^sub>E E R (f x)" shows "doE { xi \ mi; fi xi } \ \\<^sub>E E R (doE { x \ m; f x })" using assms by (simp add: pw_ele_iff refine_pw_simps) blast text \Order of this lemmas matters!\ lemmas [refine] = ebind_refine EASSERT_bind_refine_left EASSUME_bind_refine_right EASSUME_bind_refine_left EASSERT_bind_refine_right thm refine(1-10) lemma ebind_refine': assumes "mi \\\<^sub>E E R' m" assumes "\xi x. \(xi,x)\R'; inres mi (Inr xi); inres m (Inr x); nofail mi; nofail m\ \ fi xi \\\<^sub>E E R (f x)" shows "doE { xi \ mi; fi xi } \ \\<^sub>E E R (doE { x \ m; f x })" using assms by (simp add: pw_ele_iff refine_pw_simps) blast lemma THROW_refine[refine]: "(ei,e)\E \ THROW ei \\\<^sub>E E R (THROW e)" by (auto simp: pw_ele_iff refine_pw_simps) lemma CATCH_refine': assumes "mi \ \\<^sub>E E' R m" assumes "\ei e. \ (ei,e)\E'; inres mi (Inl ei); inres m (Inl e); nofail mi; nofail m \ \ hi ei \\\<^sub>E E R (h e)" shows "CATCH mi hi \ \\<^sub>E E R (CATCH m h)" using assms by (simp add: pw_ele_iff refine_pw_simps) blast lemma CATCH_refine[refine]: assumes "mi \ \\<^sub>E E' R m" assumes "\ei e. \ (ei,e)\E' \ \ hi ei \\\<^sub>E E R (h e)" shows "CATCH mi hi \ \\<^sub>E E R (CATCH m h)" using assms CATCH_refine' by metis lemma CHECK_refine[refine]: assumes "\i \ \" assumes "\\ \ (msgi,msg)\E" shows "CHECK \i msgi \\\<^sub>E E Id (CHECK \ msg)" using assms by (auto simp: pw_ele_iff refine_pw_simps) text \This must be declared after @{thm CHECK_refine}!\ lemma CHECK_bind_refine[refine]: assumes "\i \ \" assumes "\\ \ (msgi,msg)\E" assumes "\ \ mi \\\<^sub>E E R m" shows "doE {CHECK \i msgi;mi} \\\<^sub>E E R (doE {CHECK \ msg; m})" using assms by (auto simp: pw_ele_iff refine_pw_simps) lemma Let_unfold_refine[refine]: assumes "f x \ \\<^sub>E E R (f' x')" shows "Let x f \ \\<^sub>E E R (Let x' f')" using assms by auto lemma Let_refine: assumes "(m,m')\R'" assumes "\x x'. (x,x')\R' \ f x \ \\<^sub>E E R (f' x')" shows "Let m (\x. f x) \\\<^sub>E E R (Let m' (\x'. f' x'))" using assms by auto lemma eif_refine[refine]: assumes "(b,b')\bool_rel" assumes "\b;b'\ \ S1 \ \\<^sub>E E R S1'" assumes "\\b;\b'\ \ S2 \ \\<^sub>E E R S2'" shows "(if b then S1 else S2) \ \\<^sub>E E R (if b' then S1' else S2')" using assms by auto (* TODO: Also add enfoldli_invar_refine *) lemma enfoldli_refine[refine]: assumes "(li, l) \ \S\list_rel" and "(si, s) \ R" and CR: "(ci, c) \ R \ bool_rel" and FR: "\xi x si s. \ (xi,x)\S; (si,s)\R; c s \ \ fi xi si \ \\<^sub>E E R (f x s)" shows "enfoldli li ci fi si \ \\<^sub>E E R (enfoldli l c f s)" unfolding enres_unfolds apply (rule nfoldli_refine) apply (rule assms(1)) apply (simp add: assms(2)) subgoal using CR[param_fo] by (auto split: sum.split simp: sum_rel_conv) subgoal apply refine_rcg applyS (auto split: sum.splits simp: sum_rel_conv) apply (rule FR[unfolded enres_unfolds]) by (auto split: sum.splits simp: sum_rel_conv) done lemma EWHILET_refine[refine]: assumes R0: "(x,x')\R" assumes COND_REF: "\x x'. \ (x,x')\R \ \ b x = b' x'" assumes STEP_REF: "\x x'. \ (x,x')\R; b x; b' x' \ \ f x \ \\<^sub>E E R (f' x')" shows "EWHILET b f x \\\<^sub>E E R (EWHILET b' f' x')" unfolding enres_unfolds apply refine_rcg using assms by (auto split: sum.splits simp: econc_fun_def) thm WHILEIT_refine lemma EWHILEIT_refine[refine]: assumes R0: "I' x' \ (x,x')\R" assumes I_REF: "\x x'. \ (x,x')\R; I' x' \ \ I x" assumes COND_REF: "\x x'. \ (x,x')\R; I x; I' x' \ \ b x = b' x'" assumes STEP_REF: "\x x'. \ (x,x')\R; b x; b' x'; I x; I' x' \ \ f x \ \\<^sub>E E R (f' x')" shows "EWHILEIT I b f x \\\<^sub>E E R (EWHILEIT I' b' f' x')" unfolding enres_unfolds apply refine_rcg using assms by (auto split: sum.splits simp: econc_fun_def) subsubsection \Refine2- heuristics\ lemma remove_eLet_refine: assumes "M \ \\<^sub>E E R (f x)" shows "M \ \\<^sub>E E R (Let x f)" using assms by auto lemma intro_eLet_refine: assumes "f x \ \\<^sub>E E R M'" shows "Let x f \ \\<^sub>E E R M'" using assms by auto lemma ebind2let_refine[refine2]: assumes "ERETURN x \ \\<^sub>E E R' M'" assumes "\x'. (x,x')\R' \ f x \ \\<^sub>E E R (f' x')" shows "Let x f \ \\<^sub>E E R (ebind M' (\x'. f' x'))" using assms apply (simp add: pw_ele_iff refine_pw_simps) apply fast done lemma ebind_Let_refine2[refine2]: "\ m' \\\<^sub>E E R' (ERETURN x); \x'. \inres m' (Inr x'); (x',x)\R'\ \ f' x' \ \\<^sub>E E R (f x) \ \ ebind m' (\x'. f' x') \ \\<^sub>E E R (Let x (\x. f x))" apply (simp add: pw_ele_iff refine_pw_simps) apply blast done lemma ebind2letRETURN_refine[refine2]: assumes "ERETURN x \ \\<^sub>E E R' M'" assumes "\x'. (x,x')\R' \ ERETURN (f x) \ \\<^sub>E E R (f' x')" shows "ERETURN (Let x f) \ \\<^sub>E E R (ebind M' (\x'. f' x'))" using assms apply (simp add: pw_ele_iff refine_pw_simps) apply fast done lemma ERETURN_as_SPEC_refine[refine2]: assumes "RELATES R" assumes "M \ ESPEC (\_. False) (\c. (c,a)\R)" shows "M \ \\<^sub>E E R (ERETURN a)" using assms by (simp add: pw_ele_iff refine_pw_simps) lemma if_ERETURN_refine[refine2]: assumes "b \ b'" assumes "\b;b'\ \ ERETURN S1 \ \\<^sub>E E R S1'" assumes "\\b;\b'\ \ ERETURN S2 \ \\<^sub>E E R S2'" shows "ERETURN (if b then S1 else S2) \ \\<^sub>E E R (if b' then S1' else S2')" (* this is nice to have for small functions, hence keep it in refine2 *) using assms by (simp add: pw_le_iff refine_pw_simps) text \Breaking down enres-monad \ definition enres_lift :: "'a nres \ (_,'a) enres" where "enres_lift m \ do { x \ m; RETURN (Inr x) }" lemma enres_lift_rule[refine_vcg]: "m\SPEC \ \ enres_lift m \ ESPEC E \" by (auto simp: pw_ele_iff pw_le_iff refine_pw_simps enres_lift_def) named_theorems_rev enres_breakdown lemma [enres_breakdown]: "ERETURN x = enres_lift (RETURN x)" "EASSERT \ = enres_lift (ASSERT \)" "doE { x \ enres_lift m; ef x } = do { x \ m; ef x }" (*"NO_MATCH (enres_lift m) em \ doE { x \ em; ef x } = do { ex \ em; case ex of Inl e \ RETURN (Inl e) | Inr x \ ef x }"*) unfolding enres_unfolds enres_lift_def apply (auto split: sum.splits simp: pw_eq_iff refine_pw_simps) done lemma [enres_breakdown]: "do { x \ m; enres_lift (f x) } = enres_lift (do { x \ m; f x })" "do { let x = v; enres_lift (f x) } = enres_lift (do { let x=v; f x })" unfolding enres_unfolds enres_lift_def apply (auto split: sum.splits simp: pw_eq_iff refine_pw_simps) done lemma [enres_breakdown]: "CATCH (enres_lift m) h = enres_lift m" unfolding enres_unfolds enres_lift_def apply (auto split: sum.splits simp: pw_eq_iff refine_pw_simps) done lemma enres_lift_fail[simp]: "enres_lift FAIL = FAIL" unfolding enres_lift_def by auto (* TODO: Also do breakdown-thm for RECT. It's exactly the same approach! *) lemma [enres_breakdown]: "EWHILEIT I c (\s. enres_lift (f s)) s = enres_lift (WHILEIT I c f s)" (is "?lhs = ?rhs") proof (rule antisym) show "?lhs \ ?rhs" unfolding enres_unfolds WHILEIT_def WHILET_def apply (rule RECT_transfer_rel'[where P="\c a. c = Inr a"]) apply (simp add: while.WHILEI_body_trimono) apply (simp add: while.WHILEI_body_trimono) apply simp apply simp by (auto simp: WHILEI_body_def enres_lift_def pw_le_iff refine_pw_simps) show "?rhs \ ?lhs" unfolding enres_unfolds WHILEIT_def WHILET_def apply (rule RECT_transfer_rel'[where P="\a c. c = Inr a"]) apply (simp add: while.WHILEI_body_trimono) apply (simp add: while.WHILEI_body_trimono) apply simp apply simp by (auto simp: WHILEI_body_def enres_lift_def pw_le_iff refine_pw_simps) qed lemma [enres_breakdown]: "EWHILET c (\s. enres_lift (f s)) s = enres_lift (WHILET c f s)" unfolding EWHILET_def WHILET_def enres_breakdown .. lemma [enres_breakdown]: "enfoldli l c (\x s. enres_lift (f x s)) s = enres_lift (nfoldli l c f s)" apply (induction l arbitrary: s) by (auto simp: enres_breakdown) lemma [enres_breakdown]: "(\(a,b). enres_lift (f a b)) = (\x. enres_lift (case x of (a,b) \ f a b))" by auto lemmas [enres_breakdown] = nres_monad_laws nres_bind_let_law lemma [enres_breakdown]: "doE { CHECK \ e; m } = (if \ then m else THROW e)" by (auto simp: enres_unfolds) lemma [enres_breakdown]: "(if b then enres_lift m else enres_lift n) = enres_lift (if b then m else n)" by simp lemma option_case_enbd[enres_breakdown]: "case_option (enres_lift fn) (\v. enres_lift (fs v)) = (\x. enres_lift (case_option fn fs x))" by (auto split: option.split) named_theorems enres_inline method opt_enres_unfold = ((unfold enres_inline)?; (unfold enres_monad_laws)?; (unfold enres_breakdown)?; (rule refl)?; (unfold enres_unfolds enres_lift_def nres_monad_laws)?; (rule refl)?) subsection \More Combinators\ subsubsection \CHECK-Monadic\ definition [enres_unfolds]: "CHECK_monadic c e \ doE { b \ c; CHECK b e }" lemma CHECK_monadic_rule_iff: "(CHECK_monadic c e \ ESPEC E P) \ (c \ ESPEC E (\r. (r \ P ()) \ (\r \ E e)))" by (auto simp: pw_ele_iff CHECK_monadic_def refine_pw_simps) lemma CHECK_monadic_pw[refine_pw_simps]: "nofail (CHECK_monadic c e) \ nofail c" "inres (CHECK_monadic c e) (Inl ee) \ (inres c (Inl ee) \ inres c (Inr False) \ ee=e)" "inres (CHECK_monadic c e) (Inr x) \ (inres c (Inr True))" unfolding CHECK_monadic_def by (auto simp: refine_pw_simps) lemma CHECK_monadic_rule[refine_vcg]: assumes "c \ ESPEC E (\r. (r \ P ()) \ (\r \ E e))" shows "CHECK_monadic c e \ ESPEC E P" using assms by (simp add: CHECK_monadic_rule_iff) lemma CHECK_monadic_refine[refine]: assumes "ci \ \\<^sub>E ER bool_rel c" assumes "(ei,e)\ER" shows "CHECK_monadic ci ei \\\<^sub>E ER unit_rel (CHECK_monadic c e)" using assms by (auto simp: pw_ele_iff refine_pw_simps) lemma CHECK_monadic_CHECK_refine[refine]: assumes "ci \ ESPEC (\e'. (e',e)\ER \ \c) (\r. r \ c)" assumes "(ei,e)\ER" shows "CHECK_monadic ci ei \\\<^sub>E ER unit_rel (CHECK c e)" using assms by (auto simp: pw_ele_iff refine_pw_simps) lemma CHECK_monadic_endb[enres_breakdown]: "CHECK_monadic (enres_lift c) e = do {b \ c; CHECK b e}" by (auto simp: enres_unfolds enres_lift_def) end diff --git a/thys/VerifyThis2019/lib/VTcomp.thy b/thys/VerifyThis2019/lib/VTcomp.thy --- a/thys/VerifyThis2019/lib/VTcomp.thy +++ b/thys/VerifyThis2019/lib/VTcomp.thy @@ -1,133 +1,133 @@ theory VTcomp imports Exc_Nres_Monad begin section \Library\ text \ This theory contains a collection of auxiliary material that was used as a library for the contest. \ lemma monadic_WHILEIT_unfold: "monadic_WHILEIT I b f s = do { ASSERT (I s); bb\b s; if bb then do { s \ f s; monadic_WHILEIT I b f s } else RETURN s }" unfolding monadic_WHILEIT_def apply (subst RECT_unfold) apply refine_mono by simp no_notation Ref.lookup ("!_" 61) no_notation Ref.update ("_ := _" 62) subsection \Specialized Rules for Foreach-Loops\ lemma nfoldli_upt_rule: assumes INTV: "lb\ub" assumes I0: "I lb \0" assumes IS: "\i \. \ lb\i; i; c \ \ \ f i \ \ SPEC (I (i+1))" assumes FNC: "\i \. \ lb\i; i\ub; I i \; \c \ \ \ P \" assumes FC: "\\. \ I ub \; c \ \ \ P \" shows "nfoldli [lb..0 \ SPEC P" apply (rule nfoldli_rule[where I="\l _ \. I (lb+length l) \"]) apply simp_all apply (simp add: I0) subgoal using IS by (metis Suc_eq_plus1 add_diff_cancel_left' eq_diff_iff le_add1 length_upt upt_eq_lel_conv) subgoal for l1 l2 \ apply (rule FNC[where i="lb + length l1"]) apply (auto simp: INTV) using INTV upt_eq_append_conv by auto apply (rule FC) using INTV by auto definition [enres_unfolds]: "efor (lb::int) ub f \ \ doE { EASSERT (lb\ub); (_,\) \ EWHILET (\(i,\). i(i,\). doE { \ \ f i \; ERETURN (i+1,\) }) (lb,\); ERETURN \ }" lemma efor_rule: assumes INTV: "lb\ub" assumes I0: "I lb \0" assumes IS: "\i \. \ lb\i; i \ \ f i \ \ ESPEC E (I (i+1))" assumes FC: "\\. \ I ub \ \ \ P \" shows "efor lb ub f \0 \ ESPEC E P" unfolding efor_def supply EWHILET_rule[where R="measure (\(i,_). nat (ub-i))" and I="\(i,\). lb\i \ i\ub \ I i \", refine_vcg] apply refine_vcg apply auto using assms apply auto done subsection \Improved Do-Notation for the \nres\-Monad\ abbreviation (do_notation) bind_doN where "bind_doN \ Refine_Basic.bind" -notation (output) bind_doN (infixr "\" 54) -notation (ASCII output) bind_doN (infixr ">>=" 54) +notation (output) bind_doN (infixl "\" 54) +notation (ASCII output) bind_doN (infixl ">>=" 54) nonterminal doN_binds and doN_bind syntax "_doN_block" :: "doN_binds \ 'a" ("doN {//(2 _)//}" [12] 62) "_doN_bind" :: "[pttrn, 'a] \ doN_bind" ("(2_ \/ _)" 13) "_doN_let" :: "[pttrn, 'a] \ doN_bind" ("(2let _ =/ _)" [1000, 13] 13) "_doN_then" :: "'a \ doN_bind" ("_" [14] 13) "_doN_final" :: "'a \ doN_binds" ("_") "_doN_cons" :: "[doN_bind, doN_binds] \ doN_binds" ("_;//_" [13, 12] 12) - "_thenM" :: "['a, 'b] \ 'c" (infixr "\" 54) + "_thenM" :: "['a, 'b] \ 'c" (infixl "\" 54) syntax (ASCII) "_doN_bind" :: "[pttrn, 'a] \ doN_bind" ("(2_ <-/ _)" 13) - "_thenM" :: "['a, 'b] \ 'c" (infixr ">>" 54) + "_thenM" :: "['a, 'b] \ 'c" (infixl ">>" 54) translations "_doN_block (_doN_cons (_doN_then t) (_doN_final e))" \ "CONST bind_doN t (\_. e)" "_doN_block (_doN_cons (_doN_bind p t) (_doN_final e))" \ "CONST bind_doN t (\p. e)" "_doN_block (_doN_cons (_doN_let p t) bs)" \ "let p = t in _doN_block bs" "_doN_block (_doN_cons b (_doN_cons c cs))" \ "_doN_block (_doN_cons b (_doN_final (_doN_block (_doN_cons c cs))))" "_doN_cons (_doN_let p t) (_doN_final s)" \ "_doN_final (let p = t in s)" "_doN_block (_doN_final e)" \ "e" "(m \ n)" \ "(m \ (\_. n))" subsection \Array Blit exposed to Sepref\ definition "op_list_blit src si dst di len \ (take di dst @ take len (drop si src) @ drop (di+len) dst)" context notes op_list_blit_def[simp] begin sepref_decl_op (no_def) list_blit : "op_list_blit" :: "[\((((src,si),dst),di),len). si+len \ length src \ di+len \ length dst]\<^sub>f ((((\A\list_rel \\<^sub>r nat_rel) \\<^sub>r \A\list_rel) \\<^sub>r nat_rel) \\<^sub>r nat_rel) \ \A\list_rel" . end lemma blit_len[simp]: "si + len \ length src \ di + len \ length dst \ length (op_list_blit src si dst di len) = length dst" by (auto simp: op_list_blit_def) context notes [fcomp_norm_unfold] = array_assn_def[symmetric] begin lemma array_blit_hnr_aux: "(uncurry4 (\src si dst di len. do { blit src si dst di len; return dst }), uncurry4 mop_list_blit) \ is_array\<^sup>k*\<^sub>anat_assn\<^sup>k*\<^sub>ais_array\<^sup>d*\<^sub>anat_assn\<^sup>k*\<^sub>anat_assn\<^sup>k \\<^sub>a is_array" apply sepref_to_hoare apply (clarsimp simp: refine_pw_simps) apply (sep_auto simp: is_array_def op_list_blit_def) done sepref_decl_impl (ismop) array_blit: array_blit_hnr_aux . end end