diff --git a/thys/Gabow_SCC/Gabow_GBG.thy b/thys/Gabow_SCC/Gabow_GBG.thy --- a/thys/Gabow_SCC/Gabow_GBG.thy +++ b/thys/Gabow_SCC/Gabow_GBG.thy @@ -1,2102 +1,2102 @@ section \Lasso Finding Algorithm for Generalized B\"uchi Graphs \label{sec:gbg}\ theory Gabow_GBG imports Gabow_Skeleton CAVA_Automata.Lasso Find_Path begin (* TODO: convenience locale, consider merging this with invariants *) locale igb_fr_graph = igb_graph G + fr_graph G for G :: "('Q,'more) igb_graph_rec_scheme" lemma igb_fr_graphI: assumes "igb_graph G" assumes "finite ((g_E G)\<^sup>* `` g_V0 G)" shows "igb_fr_graph G" proof - interpret igb_graph G by fact show ?thesis using assms(2) by unfold_locales qed text \ We implement an algorithm that computes witnesses for the non-emptiness of Generalized B\"uchi Graphs (GBG). \ section \Specification\ context igb_graph begin definition ce_correct \ \Specifies a correct counter-example\ where "ce_correct Vr Vl \ (\pr pl. Vr \ E\<^sup>*``V0 \ Vl \ E\<^sup>*``V0 \ \Only reachable nodes are covered\ \ set pr\Vr \ set pl\Vl \ \The paths are inside the specified sets\ \ Vl\Vl \ (E \ Vl\Vl)\<^sup>* \ \\Vl\ is mutually connected\ \ Vl\Vl \ E \ {} \ \\Vl\ is non-trivial\ \ is_lasso_prpl (pr,pl)) \ \Paths form a lasso\ " definition find_ce_spec :: "('Q set \ 'Q set) option nres" where "find_ce_spec \ SPEC (\r. case r of None \ (\prpl. \is_lasso_prpl prpl) | Some (Vr,Vl) \ ce_correct Vr Vl )" definition find_lasso_spec :: "('Q list \ 'Q list) option nres" where "find_lasso_spec \ SPEC (\r. case r of None \ (\prpl. \is_lasso_prpl prpl) | Some prpl \ is_lasso_prpl prpl )" end section \Invariant Extension\ text \Extension of the outer invariant:\ context igb_fr_graph begin definition no_acc_over \ \Specifies that there is no accepting cycle touching a set of nodes\ where "no_acc_over D \ \(\v\D. \pl. pl\[] \ path E v pl v \ (\iq\set pl. i\acc q))" definition "fgl_outer_invar_ext \ \it (brk,D). case brk of None \ no_acc_over D | Some (Vr,Vl) \ ce_correct Vr Vl" definition "fgl_outer_invar \ \it (brk,D). case brk of None \ outer_invar it D \ no_acc_over D | Some (Vr,Vl) \ ce_correct Vr Vl" end text \Extension of the inner invariant:\ locale fgl_invar_loc = invar_loc G v0 D0 p D pE + igb_graph G for G :: "('Q, 'more) igb_graph_rec_scheme" and v0 D0 and brk :: "('Q set \ 'Q set) option" and p D pE + assumes no_acc: "brk=None \ \(\v pl. pl\[] \ path lvE v pl v \ (\iq\set pl. i\acc q))" \ \No accepting cycle over visited edges\ assumes acc: "brk=Some (Vr,Vl) \ ce_correct Vr Vl" begin lemma locale_this: "fgl_invar_loc G v0 D0 brk p D pE" by unfold_locales lemma invar_loc_this: "invar_loc G v0 D0 p D pE" by unfold_locales lemma eas_gba_graph_this: "igb_graph G" by unfold_locales end definition (in igb_graph) "fgl_invar v0 D0 \ \(brk, p, D, pE). fgl_invar_loc G v0 D0 brk p D pE" section \Definition of the Lasso-Finding Algorithm\ context igb_fr_graph begin definition find_ce :: "('Q set \ 'Q set) option nres" where "find_ce \ do { let D = {}; (brk,_)\FOREACHci fgl_outer_invar V0 (\(brk,_). brk=None) (\v0 (brk,D0). do { if v0\D0 then do { let s = (None,initial v0 D0); (brk,p,D,pE) \ WHILEIT (fgl_invar v0 D0) (\(brk,p,D,pE). brk=None \ p \ []) (\(_,p,D,pE). do { \ \Select edge from end of path\ (vo,(p,D,pE)) \ select_edge (p,D,pE); ASSERT (p\[]); case vo of Some v \ do { if v \ \(set p) then do { \ \Collapse\ let (p,D,pE) = collapse v (p,D,pE); ASSERT (p\[]); if \iq\last p. i\acc q then RETURN (Some (\(set (butlast p)),last p),p,D,pE) else RETURN (None,p,D,pE) } else if v\D then do { \ \Edge to new node. Append to path\ RETURN (None,push v (p,D,pE)) } else RETURN (None,p,D,pE) } | None \ do { \ \No more outgoing edges from current node on path\ ASSERT (pE \ last p \ UNIV = {}); RETURN (None,pop (p,D,pE)) } }) s; ASSERT (brk=None \ (p=[] \ pE={})); RETURN (brk,D) } else RETURN (brk,D0) }) (None,D); RETURN brk }" end section \Invariant Preservation\ context igb_fr_graph begin definition "fgl_invar_part \ \(brk, p, D, pE). fgl_invar_loc_axioms G brk p D pE" lemma fgl_outer_invarI[intro?]: "\ brk=None \ outer_invar it D; \brk=None \ outer_invar it D\ \ fgl_outer_invar_ext it (brk,D)\ \ fgl_outer_invar it (brk,D)" unfolding outer_invar_def fgl_outer_invar_ext_def fgl_outer_invar_def apply (auto split: prod.splits option.splits) done lemma fgl_invarI[intro?]: "\ invar v0 D0 PDPE; invar v0 D0 PDPE \ fgl_invar_part (B,PDPE)\ \ fgl_invar v0 D0 (B,PDPE)" unfolding invar_def fgl_invar_part_def fgl_invar_def apply (simp split: prod.split_asm) apply intro_locales apply (simp add: invar_loc_def) apply assumption done lemma fgl_invar_initial: assumes OINV: "fgl_outer_invar it (None,D0)" assumes A: "v0\it" "v0\D0" shows "fgl_invar_part (None, initial v0 D0)" proof - from OINV interpret outer_invar_loc G it D0 by (simp add: fgl_outer_invar_def outer_invar_def) from OINV have no_acc: "no_acc_over D0" by (simp add: fgl_outer_invar_def fgl_outer_invar_ext_def) { fix v pl assume "pl \ []" and P: "path (vE [{v0}] D0 (E \ {v0} \ UNIV)) v pl v" hence 1: "v\D0" by (cases pl) (auto simp: path_cons_conv vE_def touched_def) have 2: "path E v pl v" using path_mono[OF vE_ss_E P] . note 1 2 } note AUX1=this show ?thesis unfolding fgl_invar_part_def apply (simp split: prod.splits add: initial_def) apply unfold_locales using \v0\D0\ using AUX1 no_acc unfolding no_acc_over_def apply blast by simp qed lemma fgl_invar_pop: assumes INV: "fgl_invar v0 D0 (None,p,D,pE)" assumes INV': "invar v0 D0 (pop (p,D,pE))" assumes NE[simp]: "p\[]" assumes NO': "pE \ last p \ UNIV = {}" shows "fgl_invar_part (None, pop (p,D,pE))" proof - from INV interpret fgl_invar_loc G v0 D0 None p D pE by (simp add: fgl_invar_def) show ?thesis apply (unfold fgl_invar_part_def pop_def) apply (simp split: prod.splits) apply unfold_locales unfolding vE_pop[OF NE] using no_acc apply auto [] apply simp done qed lemma fgl_invar_collapse_ce_aux: assumes INV: "invar v0 D0 (p, D, pE)" assumes NE[simp]: "p\[]" assumes NONTRIV: "vE p D pE \ (last p \ last p) \ {}" assumes ACC: "\iq\last p. i\acc q" shows "fgl_invar_part (Some (\(set (butlast p)), last p), p, D, pE)" proof - from INV interpret invar_loc G v0 D0 p D pE by (simp add: invar_def) txt \The last collapsed node on the path contains states from all accepting sets. As it is strongly connected and reachable, we get a counter-example. Here, we explicitely construct the lasso.\ let ?Er = "E \ (\(set (butlast p)) \ UNIV)" txt \We choose a node in the last Cnode, that is reachable only using former Cnodes.\ obtain w where "(v0,w)\?Er\<^sup>*" "w\last p" proof cases assume "length p = 1" hence "v0\last p" using root_v0 by (cases p) auto thus thesis by (auto intro: that) next assume "length p\1" hence "length p > 1" by (cases p) auto hence "Suc (length p - 2) < length p" by auto from p_connected'[OF this] obtain u v where UIP: "u\p!(length p - 2)" and VIP: "v\p!(length p - 1)" and "(u,v)\lvE" using \length p > 1\ by auto from root_v0 have V0IP: "v0\p!0" by (cases p) auto from VIP have "v\last p" by (cases p rule: rev_cases) auto from pathI[OF V0IP UIP] \length p > 1\ have "(v0,u)\(lvE \ \(set (butlast p)) \ \(set (butlast p)))\<^sup>*" (is "_ \ \\<^sup>*") by (simp add: path_seg_butlast) also have "\ \ ?Er" using lvE_ss_E by auto finally (rtrancl_mono_mp[rotated]) have "(v0,u)\?Er\<^sup>*" . also note \(u,v)\lvE\ UIP hence "(u,v)\?Er" using lvE_ss_E \length p > 1\ apply (auto simp: Bex_def in_set_conv_nth) by (metis One_nat_def Suc_lessE \Suc (length p - 2) < length p\ diff_Suc_1 length_butlast nth_butlast) finally show ?thesis by (rule that) fact qed then obtain "pr" where P_REACH: "path E v0 pr w" and R_SS: "set pr \ \(set (butlast p))" apply - apply (erule rtrancl_is_path) apply (frule path_nodes_edges) apply (auto dest!: order_trans[OF _ image_Int_subset] dest: path_mono[of _ E, rotated]) done have [simp]: "last p = p!(length p - 1)" by (cases p rule: rev_cases) auto txt \From that node, we construct a lasso by inductively appending a path for each accepting set\ { fix na assume na_def: "na = num_acc" have "\pl. pl\[] \ path (lvE \ last p\last p) w pl w \ (\iq\set pl. i\acc q)" using ACC unfolding na_def[symmetric] proof (induction na) case 0 from NONTRIV obtain u v where "(u,v)\lvE \ last p \ last p" "u\last p" "v\last p" by auto from cnode_connectedI \w\last p\ \u\last p\ have "(w,u)\(lvE \ last p \ last p)\<^sup>*" by auto also note \(u,v)\lvE \ last p \ last p\ also (rtrancl_into_trancl1) from cnode_connectedI \v\last p\ \w\last p\ have "(v,w)\(lvE \ last p \ last p)\<^sup>*" by auto finally obtain pl where "pl\[]" "path (lvE \ last p \ last p) w pl w" by (rule trancl_is_path) thus ?case by auto next case (Suc n) from Suc.prems have "\iq\last p. i\acc q" by auto with Suc.IH obtain pl where IH: "pl\[]" "path (lvE \ last p \ last p) w pl w" "\iq\set pl. i\acc q" by blast from Suc.prems obtain v where "v\last p" and "n\acc v" by auto from cnode_connectedI \w\last p\ \v\last p\ have "(w,v)\(lvE \ last p \ last p)\<^sup>*" by auto then obtain pl1 where P1: "path (lvE \ last p \ last p) w pl1 v" by (rule rtrancl_is_path) also from cnode_connectedI \w\last p\ \v\last p\ have "(v,w)\(lvE \ last p \ last p)\<^sup>*" by auto then obtain pl2 where P2: "path (lvE \ last p \ last p) v pl2 w" by (rule rtrancl_is_path) also (path_conc) note IH(2) finally (path_conc) have P: "path (lvE \ last p \ last p) w (pl1@pl2@pl) w" by simp moreover from IH(1) have "pl1@pl2@pl \ []" by simp moreover have "\i'q\set (pl1@pl2@pl). i'\acc q" using IH(3) by auto moreover have "v\set (pl1@pl2@pl)" using P1 P2 P IH(1) apply (cases pl2, simp_all add: path_cons_conv path_conc_conv) apply (cases pl, simp_all add: path_cons_conv) apply (cases pl1, simp_all add: path_cons_conv) done with \n\acc v\ have "\q\set (pl1@pl2@pl). n\acc q" by auto ultimately show ?case apply (intro exI conjI) apply assumption+ apply (auto elim: less_SucE) done qed } then obtain pl where pl: "pl\[]" "path (lvE \ last p\last p) w pl w" "\iq\set pl. i\acc q" by blast hence "path E w pl w" and L_SS: "set pl \ last p" apply - apply (frule path_mono[of _ E, rotated]) using lvE_ss_E apply auto [2] apply (drule path_nodes_edges) apply (drule order_trans[OF _ image_Int_subset]) apply auto [] done have LASSO: "is_lasso_prpl (pr,pl)" unfolding is_lasso_prpl_def is_lasso_prpl_pre_def using \path E w pl w\ P_REACH pl by auto from p_sc have "last p \ last p \ (lvE \ last p \ last p)\<^sup>*" by auto with lvE_ss_E have VL_CLOSED: "last p \ last p \ (E \ last p \ last p)\<^sup>*" apply (erule_tac order_trans) apply (rule rtrancl_mono) by blast have NONTRIV': "last p \ last p \ E \ {}" by (metis Int_commute NONTRIV disjoint_mono lvE_ss_E subset_refl) from order_trans[OF path_touched touched_reachable] have LP_REACH: "last p \ E\<^sup>*``V0" and BLP_REACH: "\(set (butlast p)) \ E\<^sup>*``V0" apply - apply (cases p rule: rev_cases) apply simp apply auto [] apply (cases p rule: rev_cases) apply simp apply auto [] done show ?thesis apply (simp add: fgl_invar_part_def) apply unfold_locales apply simp using LASSO R_SS L_SS VL_CLOSED NONTRIV' LP_REACH BLP_REACH unfolding ce_correct_def apply simp apply blast done qed lemma fgl_invar_collapse_ce: fixes u v assumes INV: "fgl_invar v0 D0 (None,p,D,pE)" defines "pE' \ pE - {(u,v)}" assumes CFMT: "(p',D',pE'') = collapse v (p,D,pE')" assumes INV': "invar v0 D0 (p',D',pE'')" assumes NE[simp]: "p\[]" assumes E: "(u,v)\pE" and "u\last p" assumes BACK: "v\\(set p)" assumes ACC: "\iq\last p'. i\acc q" defines i_def: "i \ idx_of p v" shows "fgl_invar_part ( Some (\(set (butlast p')), last p'), collapse v (p,D,pE'))" proof - from CFMT have p'_def: "p' = collapse_aux p i" and [simp]: "D'=D" "pE''=pE'" by (simp_all add: collapse_def i_def) from INV interpret fgl_invar_loc G v0 D0 None p D pE by (simp add: fgl_invar_def) from idx_of_props[OF BACK] have "ip!i" by (simp_all add: i_def) have "u\last p'" using \u\last p\ \i unfolding p'_def collapse_aux_def apply (simp add: last_drop last_snoc) by (metis Misc.last_in_set drop_eq_Nil last_drop not_le) moreover have "v\last p'" using \v\p!i\ \i unfolding p'_def collapse_aux_def by (metis UnionI append_Nil Cons_nth_drop_Suc in_set_conv_decomp last_snoc) ultimately have "vE p' D pE' \ last p' \ last p' \ {}" unfolding p'_def pE'_def by (auto simp: E) have "p'\[]" by (simp add: p'_def collapse_aux_def) have [simp]: "collapse v (p,D,pE') = (p',D,pE')" unfolding collapse_def p'_def i_def by simp show ?thesis apply simp apply (rule fgl_invar_collapse_ce_aux) using INV' apply simp apply fact+ done qed lemma fgl_invar_collapse_nce: fixes u v assumes INV: "fgl_invar v0 D0 (None,p,D,pE)" defines "pE' \ pE - {(u,v)}" assumes CFMT: "(p',D',pE'') = collapse v (p,D,pE')" assumes INV': "invar v0 D0 (p',D',pE'')" assumes NE[simp]: "p\[]" assumes E: "(u,v)\pE" and "u\last p" assumes BACK: "v\\(set p)" assumes NACC: "jq\last p'. j\acc q" defines "i \ idx_of p v" shows "fgl_invar_part (None, collapse v (p,D,pE'))" proof - from CFMT have p'_def: "p' = collapse_aux p i" and [simp]: "D'=D" "pE''=pE'" by (simp_all add: collapse_def i_def) have [simp]: "collapse v (p,D,pE') = (p',D,pE')" by (simp add: collapse_def p'_def i_def) from INV interpret fgl_invar_loc G v0 D0 None p D pE by (simp add: fgl_invar_def) from INV' interpret inv': invar_loc G v0 D0 p' D pE' by (simp add: invar_def) define vE' where "vE' = vE p' D pE'" have vE'_alt: "vE' = insert (u,v) lvE" by (simp add: vE'_def p'_def pE'_def E) from idx_of_props[OF BACK] have "ip!i" by (simp_all add: i_def) have "u\last p'" using \u\last p\ \i unfolding p'_def collapse_aux_def apply (simp add: last_drop last_snoc) by (metis Misc.last_in_set drop_eq_Nil last_drop leD) moreover have "v\last p'" using \v\p!i\ \i unfolding p'_def collapse_aux_def by (metis UnionI append_Nil Cons_nth_drop_Suc in_set_conv_decomp last_snoc) ultimately have "vE' \ last p' \ last p' \ {}" unfolding vE'_alt by (auto) have "p'\[]" by (simp add: p'_def collapse_aux_def) { txt \ We show that no visited strongly connected component contains states from all acceptance sets.\ fix w pl txt \For this, we chose a non-trivial loop inside the visited edges\ assume P: "path vE' w pl w" and NT: "pl\[]" txt \And show that there is one acceptance set disjoint with the nodes of the loop\ have "\iq\set pl. i\acc q" proof cases assume "set pl \ last p' = {}" \ \Case: The loop is outside the last Cnode\ with path_restrict[OF P] \u\last p'\ \v\last p'\ have "path lvE w pl w" apply - apply (drule path_mono[of _ lvE, rotated]) unfolding vE'_alt by auto with no_acc NT show ?thesis by auto next assume "set pl \ last p' \ {}" \ \Case: The loop touches the last Cnode\ txt \Then, the loop must be completely inside the last CNode\ from inv'.loop_in_lastnode[folded vE'_def, OF P \p'\[]\ this] have "w\last p'" "set pl \ last p'" . with NACC show ?thesis by blast qed } note AUX_no_acc = this show ?thesis apply (simp add: fgl_invar_part_def) apply unfold_locales using AUX_no_acc[unfolded vE'_def] apply auto [] apply simp done qed lemma collapse_ne: "([],D',pE') \ collapse v (p,D,pE)" by (simp add: collapse_def collapse_aux_def Let_def) lemma fgl_invar_push: assumes INV: "fgl_invar v0 D0 (None,p,D,pE)" assumes BRK[simp]: "brk=None" assumes NE[simp]: "p\[]" assumes E: "(u,v)\pE" and UIL: "u\last p" assumes VNE: "v\\(set p)" "v\D" assumes INV': "invar v0 D0 (push v (p,D,pE - {(u,v)}))" shows "fgl_invar_part (None, push v (p,D,pE - {(u,v)}))" proof - from INV interpret fgl_invar_loc G v0 D0 None p D pE by (simp add: fgl_invar_def) define pE' where "pE' = (pE - {(u,v)} \ E\{v}\UNIV)" have [simp]: "push v (p,D,pE - {(u,v)}) = (p@[{v}],D,pE')" by (simp add: push_def pE'_def) from INV' interpret inv': invar_loc G v0 D0 "(p@[{v}])" D "pE'" by (simp add: invar_def) note defs_fold = vE_push[OF E UIL VNE, folded pE'_def] { txt \We show that there still is no loop that contains all accepting nodes. For this, we choose some loop.\ fix w pl assume P: "path (insert (u,v) lvE) w pl w" and [simp]: "pl\[]" have "\iq\set pl. i\acc q" proof cases assume "v\set pl" \ \Case: The newly pushed last cnode is on the loop\ txt \Then the loop is entirely on the last cnode\ with inv'.loop_in_lastnode[unfolded defs_fold, OF P] have [simp]: "w=v" and SPL: "set pl = {v}" by auto txt \However, we then either have that the last cnode is contained in the last but one cnode, or that there is a visited edge inside the last cnode.\ from P SPL have "u=v \ (v,v)\lvE" apply (cases pl) apply (auto simp: path_cons_conv) apply (case_tac list) apply (auto simp: path_cons_conv) done txt \Both leads to a contradiction\ hence False proof assume "u=v" \ \This is impossible, as @{text "u"} was on the original path, but @{text "v"} was not\ with UIL VNE show False by auto next assume "(v,v)\lvE" \ \This is impossible, as all visited edges are from touched nodes, but @{text "v"} was untouched\ with vE_touched VNE show False unfolding touched_def by auto qed thus ?thesis .. next assume A: "v\set pl" \ \Case: The newly pushed last cnode is not on the loop\ txt \Then, the path lays inside the old visited edges\ have "path lvE w pl w" proof - have "w\set pl" using P by (cases pl) (auto simp: path_cons_conv) with A show ?thesis using path_restrict[OF P] apply - apply (drule path_mono[of _ lvE, rotated]) apply (cases pl, auto) [] apply assumption done qed txt \And thus, the proposition follows from the invariant on the old state\ with no_acc show ?thesis apply simp using \pl\[]\ by blast qed } note AUX_no_acc = this show ?thesis unfolding fgl_invar_part_def apply simp apply unfold_locales unfolding defs_fold using AUX_no_acc apply auto [] apply simp done qed lemma fgl_invar_skip: assumes INV: "fgl_invar v0 D0 (None,p,D,pE)" assumes BRK[simp]: "brk=None" assumes NE[simp]: "p\[]" assumes E: "(u,v)\pE" and UIL: "u\last p" assumes VID: "v\D" assumes INV': "invar v0 D0 (p, D, (pE - {(u,v)}))" shows "fgl_invar_part (None, p, D, (pE - {(u,v)}))" proof - from INV interpret fgl_invar_loc G v0 D0 None p D pE by (simp add: fgl_invar_def) from INV' interpret inv': invar_loc G v0 D0 p D "(pE - {(u,v)})" by (simp add: invar_def) { txt \We show that there still is no loop that contains all accepting nodes. For this, we choose some loop.\ fix w pl assume P: "path (insert (u,v) lvE) w pl w" and [simp]: "pl\[]" from P have "\iq\set pl. i\acc q" proof (cases rule: path_edge_rev_cases) case no_use \ \Case: The loop does not use the new edge\ txt \The proposition follows from the invariant for the old state\ with no_acc show ?thesis apply simp using \pl\[]\ by blast next case (split p1 p2) \ \Case: The loop uses the new edge\ txt \As done is closed under transitions, the nodes of the edge have already been visited\ from split(2) D_closed_vE_rtrancl have WID: "w\D" using VID by (auto dest!: path_is_rtrancl) from split(1) WID D_closed_vE_rtrancl have "u\D" apply (cases rule: path_edge_cases) apply (auto dest!: path_is_rtrancl) done txt \Which is a contradition to the assumptions\ with UIL p_not_D have False by (cases p rule: rev_cases) auto thus ?thesis .. qed } note AUX_no_acc = this show ?thesis apply (simp add: fgl_invar_part_def) apply unfold_locales unfolding vE_remove[OF NE E] using AUX_no_acc apply auto [] apply simp done qed lemma fgl_outer_invar_initial: "outer_invar V0 {} \ fgl_outer_invar_ext V0 (None, {})" unfolding fgl_outer_invar_ext_def apply (simp add: no_acc_over_def) done lemma fgl_outer_invar_brk: assumes INV: "fgl_invar v0 D0 (Some (Vr,Vl),p,D,pE)" shows "fgl_outer_invar_ext anyIt (Some (Vr,Vl), anyD)" proof - from INV interpret fgl_invar_loc G v0 D0 "Some (Vr,Vl)" p D pE by (simp add: fgl_invar_def) from acc show ?thesis by (simp add: fgl_outer_invar_ext_def) qed lemma fgl_outer_invar_newnode_nobrk: assumes A: "v0\D0" "v0\it" assumes OINV: "fgl_outer_invar it (None,D0)" assumes INV: "fgl_invar v0 D0 (None,[],D',pE)" shows "fgl_outer_invar_ext (it-{v0}) (None,D')" proof - from OINV interpret outer_invar_loc G it D0 unfolding fgl_outer_invar_def outer_invar_def by simp from INV interpret inv: fgl_invar_loc G v0 D0 None "[]" D' pE unfolding fgl_invar_def by simp from inv.pE_fin have [simp]: "pE = {}" by simp { fix v pl assume A: "v\D'" "path E v pl v" have "path (E \ D' \ UNIV) v pl v" apply (rule path_mono[OF _ path_restrict_closed[OF inv.D_closed A]]) by auto } note AUX1=this show ?thesis unfolding fgl_outer_invar_ext_def apply simp using inv.no_acc AUX1 apply (auto simp add: vE_def touched_def no_acc_over_def) [] done qed lemma fgl_outer_invar_newnode: assumes A: "v0\D0" "v0\it" assumes OINV: "fgl_outer_invar it (None,D0)" assumes INV: "fgl_invar v0 D0 (brk,p,D',pE)" assumes CASES: "(\Vr Vl. brk = Some (Vr, Vl)) \ p = []" shows "fgl_outer_invar_ext (it-{v0}) (brk,D')" using CASES apply (elim disjE1) using fgl_outer_invar_brk[of v0 D0 _ _ p D' pE] INV apply - apply (auto, assumption) [] using fgl_outer_invar_newnode_nobrk[OF A] OINV INV apply auto [] done lemma fgl_outer_invar_Dnode: assumes "fgl_outer_invar it (None, D)" "v\D" shows "fgl_outer_invar_ext (it - {v}) (None, D)" using assms by (auto simp: fgl_outer_invar_def fgl_outer_invar_ext_def) lemma fgl_fin_no_lasso: assumes A: "fgl_outer_invar {} (None, D)" assumes B: "is_lasso_prpl prpl" shows "False" proof - obtain "pr" pl where [simp]: "prpl = (pr,pl)" by (cases prpl) from A have NA: "no_acc_over D" by (simp add: fgl_outer_invar_def fgl_outer_invar_ext_def) from A have "outer_invar {} D" by (simp add: fgl_outer_invar_def) with fin_outer_D_is_reachable have [simp]: "D=E\<^sup>*``V0" by simp from NA B show False apply (simp add: no_acc_over_def is_lasso_prpl_def is_lasso_prpl_pre_def) apply clarsimp apply (blast dest: path_is_rtrancl) done qed lemma fgl_fin_lasso: assumes A: "fgl_outer_invar it (Some (Vr,Vl), D)" shows "ce_correct Vr Vl" using A by (simp add: fgl_outer_invar_def fgl_outer_invar_ext_def) lemmas fgl_invar_preserve = fgl_invar_initial fgl_invar_push fgl_invar_pop fgl_invar_collapse_ce fgl_invar_collapse_nce fgl_invar_skip fgl_outer_invar_newnode fgl_outer_invar_Dnode invar_initial outer_invar_initial fgl_invar_initial fgl_outer_invar_initial fgl_fin_no_lasso fgl_fin_lasso end section \Main Correctness Proof\ context igb_fr_graph begin lemma outer_invar_from_fgl_invarI: "fgl_outer_invar it (None,D) \ outer_invar it D" unfolding fgl_outer_invar_def outer_invar_def by (simp split: prod.splits) lemma invar_from_fgl_invarI: "fgl_invar v0 D0 (B,PDPE) \ invar v0 D0 PDPE" unfolding fgl_invar_def invar_def apply (simp split: prod.splits) unfolding fgl_invar_loc_def by simp theorem find_ce_correct: "find_ce \ find_ce_spec" proof - note [simp del] = Union_iff show ?thesis unfolding find_ce_def find_ce_spec_def select_edge_def select_def apply (refine_rcg WHILEIT_rule[where R="inv_image (abs_wf_rel v0) snd" for v0] refine_vcg ) using [[goals_limit = 5]] apply (vc_solve rec: fgl_invarI fgl_outer_invarI intro: invar_from_fgl_invarI outer_invar_from_fgl_invarI dest!: sym[of "collapse a b" for a b] simp: collapse_ne simp: pE_fin'[OF invar_from_fgl_invarI] finite_V0 solve: invar_preserve solve: asm_rl[of "_ \ _ = {}"] solve: fgl_invar_preserve) done qed end section "Emptiness Check" text \Using the lasso-finding algorithm, we can define an emptiness check\ context igb_fr_graph begin definition "abs_is_empty \ do { ce \ find_ce; RETURN (ce = None) }" theorem abs_is_empty_correct: "abs_is_empty \ SPEC (\res. res \ (\r. \is_acc_run r))" unfolding abs_is_empty_def apply (refine_rcg refine_vcg order_trans[OF find_ce_correct, unfolded find_ce_spec_def]) unfolding ce_correct_def using lasso_accepted accepted_lasso apply (clarsimp split: option.splits) apply (metis is_lasso_prpl_of_lasso surj_pair) by (metis is_lasso_prpl_conv) definition "abs_is_empty_ce \ do { ce \ find_ce; case ce of None \ RETURN None | Some (Vr,Vl) \ do { ASSERT (\pr pl. set pr \ Vr \ set pl \ Vl \ Vl \ Vl \ (E \ Vl\Vl)\<^sup>* \ is_lasso_prpl (pr,pl)); (pr,pl) \ SPEC (\(pr,pl). set pr \ Vr \ set pl \ Vl \ Vl \ Vl \ (E \ Vl\Vl)\<^sup>* \ is_lasso_prpl (pr,pl)); RETURN (Some (pr,pl)) } }" theorem abs_is_empty_ce_correct: "abs_is_empty_ce \ SPEC (\res. case res of None \ (\r. \is_acc_run r) | Some (pr,pl) \ is_acc_run (pr\pl\<^sup>\) )" unfolding abs_is_empty_ce_def apply (refine_rcg refine_vcg order_trans[OF find_ce_correct, unfolded find_ce_spec_def]) apply (clarsimp_all simp: ce_correct_def) using accepted_lasso finite_reachableE_V0 apply (metis is_lasso_prpl_of_lasso surj_pair) apply blast apply (simp add: lasso_prpl_acc_run) done end section \Refinement\ text \ In this section, we refine the lasso finding algorithm to use efficient data structures. First, we explicitely keep track of the set of acceptance classes for every c-node on the path. Second, we use Gabow's data structure to represent the path. \ subsection \Addition of Explicit Accepting Sets\ text \In a first step, we explicitely keep track of the current set of acceptance classes for every c-node on the path.\ type_synonym 'a abs_gstate = "nat set list \ 'a abs_state" type_synonym 'a ce = "('a set \ 'a set) option" type_synonym 'a abs_gostate = "'a ce \ 'a set" context igb_fr_graph begin definition gstate_invar :: "'Q abs_gstate \ bool" where "gstate_invar \ \(a,p,D,pE). a = map (\V. \(acc`V)) p" definition "gstate_rel \ br snd gstate_invar" lemma gstate_rel_sv[relator_props,simp,intro!]: "single_valued gstate_rel" by (simp add: gstate_rel_def) definition (in -) gcollapse_aux :: "nat set list \ 'a set list \ nat \ nat set list \ 'a set list" where "gcollapse_aux a p i \ (take i a @ [\(set (drop i a))],take i p @ [\(set (drop i p))])" definition (in -) gcollapse :: "'a \ 'a abs_gstate \ 'a abs_gstate" where "gcollapse v APDPE \ let (a,p,D,pE)=APDPE; i=idx_of p v; (a,p) = gcollapse_aux a p i in (a,p,D,pE)" definition "gpush v s \ let (a,s) = s in (a@[acc v],push v s)" definition "gpop s \ let (a,s) = s in (butlast a,pop s)" definition ginitial :: "'Q \ 'Q abs_gostate \ 'Q abs_gstate" where "ginitial v0 s0 \ ([acc v0], initial v0 (snd s0))" definition goinitial :: "'Q abs_gostate" where "goinitial \ (None,{})" definition go_is_no_brk :: "'Q abs_gostate \ bool" where "go_is_no_brk s \ fst s = None" definition goD :: "'Q abs_gostate \ 'Q set" where "goD s \ snd s" definition goBrk :: "'Q abs_gostate \ 'Q ce" where "goBrk s \ fst s" definition gto_outer :: "'Q ce \ 'Q abs_gstate \ 'Q abs_gostate" where "gto_outer brk s \ let (A,p,D,pE)=s in (brk,D)" definition "gselect_edge s \ do { let (a,s)=s; (r,s)\select_edge s; RETURN (r,a,s) }" definition gfind_ce :: "('Q set \ 'Q set) option nres" where "gfind_ce \ do { let os = goinitial; os\FOREACHci fgl_outer_invar V0 (go_is_no_brk) (\v0 s0. do { if v0\goD s0 then do { let s = (None,ginitial v0 s0); (brk,a,p,D,pE) \ WHILEIT (\(brk,a,s). fgl_invar v0 (goD s0) (brk,s)) (\(brk,a,p,D,pE). brk=None \ p \ []) (\(_,a,p,D,pE). do { \ \Select edge from end of path\ (vo,(a,p,D,pE)) \ gselect_edge (a,p,D,pE); ASSERT (p\[]); case vo of Some v \ do { if v \ \(set p) then do { \ \Collapse\ let (a,p,D,pE) = gcollapse v (a,p,D,pE); ASSERT (p\[]); ASSERT (a\[]); if last a = {0..(set (butlast p)),last p),a,p,D,pE) else RETURN (None,a,p,D,pE) } else if v\D then do { \ \Edge to new node. Append to path\ RETURN (None,gpush v (a,p,D,pE)) } else RETURN (None,a,p,D,pE) } | None \ do { \ \No more outgoing edges from current node on path\ ASSERT (pE \ last p \ UNIV = {}); RETURN (None,gpop (a,p,D,pE)) } }) s; ASSERT (brk=None \ (p=[] \ pE={})); RETURN (gto_outer brk (a,p,D,pE)) } else RETURN s0 }) os; RETURN (goBrk os) }" lemma gcollapse_refine: "\(v',v)\Id; (s',s)\gstate_rel\ \ (gcollapse v' s',collapse v s)\gstate_rel" unfolding gcollapse_def collapse_def collapse_aux_def gcollapse_aux_def apply (simp add: gstate_rel_def br_def Let_def) unfolding gstate_invar_def[abs_def] apply (auto split: prod.splits simp: take_map drop_map) done lemma gpush_refine: "\(v',v)\Id; (s',s)\gstate_rel\ \ (gpush v' s',push v s)\gstate_rel" unfolding gpush_def push_def apply (simp add: gstate_rel_def br_def) unfolding gstate_invar_def[abs_def] apply (auto split: prod.splits) done lemma gpop_refine: "\(s',s)\gstate_rel\ \ (gpop s',pop s)\gstate_rel" unfolding gpop_def pop_def apply (simp add: gstate_rel_def br_def) unfolding gstate_invar_def[abs_def] apply (auto split: prod.splits simp: map_butlast) done lemma ginitial_refine: "(ginitial x (None, b), initial x b) \ gstate_rel" unfolding ginitial_def gstate_rel_def br_def gstate_invar_def initial_def by auto lemma oinitial_b_refine: "((None,{}),(None,{}))\Id\\<^sub>rId" by simp lemma gselect_edge_refine: "\(s',s)\gstate_rel\ \ gselect_edge s' \\(\Id\option_rel \\<^sub>r gstate_rel) (select_edge s)" unfolding gselect_edge_def select_edge_def apply (simp add: pw_le_iff refine_pw_simps prod_rel_sv split: prod.splits option.splits) apply (auto simp: gstate_rel_def br_def gstate_invar_def) done lemma last_acc_impl: assumes "p\[]" assumes "((a',p',D',pE'),(p,D,pE))\gstate_rel" shows "(last a' = {0..iq\last p. i\acc q)" using assms acc_bound unfolding gstate_rel_def br_def gstate_invar_def by (auto simp: last_map) lemma fglr_aux1: assumes V: "(v',v)\Id" and S: "(s',s)\gstate_rel" and P: "\a' p' D' pE' p D pE. ((a',p',D',pE'),(p,D,pE))\gstate_rel \ f' a' p' D' pE' \\R (f p D pE)" shows "(let (a',p',D',pE') = gcollapse v' s' in f' a' p' D' pE') \ \R (let (p,D,pE) = collapse v s in f p D pE)" apply (auto split: prod.splits) apply (rule P) using gcollapse_refine[OF V S] apply simp done lemma gstate_invar_empty: "gstate_invar (a,[],D,pE) \ a=[]" "gstate_invar ([],p,D,pE) \ p=[]" by (auto simp add: gstate_invar_def) lemma find_ce_refine: "gfind_ce \\Id find_ce" unfolding gfind_ce_def find_ce_def unfolding goinitial_def go_is_no_brk_def[abs_def] goD_def goBrk_def gto_outer_def using [[goals_limit = 1]] apply (refine_rcg gselect_edge_refine prod_relI[OF IdI gpop_refine] prod_relI[OF IdI gpush_refine] fglr_aux1 last_acc_impl oinitial_b_refine inj_on_id ) apply refine_dref_type apply (simp_all add: ginitial_refine) apply (vc_solve (nopre) solve: asm_rl simp: gstate_rel_def br_def gstate_invar_empty) done end subsection \Refinement to Gabow's Data Structure\ subsubsection \Preliminaries\ definition Un_set_drop_impl :: "nat \ 'a set list \ 'a set nres" \ \Executable version of @{text "\set (drop i A)"}, using indexing to access @{text "A"}\ where "Un_set_drop_impl i A \ do { (_,res) \ WHILET (\(i,res). i < length A) (\(i,res). do { ASSERT (i res; let i = i + 1; RETURN (i,res) }) (i,{}); RETURN res }" lemma Un_set_drop_impl_correct: "Un_set_drop_impl i A \ SPEC (\r. r=\(set (drop i A)))" unfolding Un_set_drop_impl_def apply (refine_rcg WHILET_rule[where I="\(i',res). res=\(set ((drop i (take i' A)))) \ i\i'" and R="measure (\(i',_). length A - i')"] refine_vcg) apply (auto simp: take_Suc_conv_app_nth) done schematic_goal Un_set_drop_code_aux: assumes [autoref_rules]: "(es_impl,{})\\R\Rs" assumes [autoref_rules]: "(un_impl,(\))\\R\Rs\\R\Rs\\R\Rs" shows "(?c,Un_set_drop_impl)\nat_rel \ \\R\Rs\as_rel \ \\R\Rs\nres_rel" unfolding Un_set_drop_impl_def[abs_def] apply (autoref (trace, keep_goal)) done concrete_definition Un_set_drop_code uses Un_set_drop_code_aux schematic_goal Un_set_drop_tr_aux: "RETURN ?c \ Un_set_drop_code es_impl un_impl i A" unfolding Un_set_drop_code_def by refine_transfer concrete_definition Un_set_drop_tr for es_impl un_impl i A uses Un_set_drop_tr_aux lemma Un_set_drop_autoref[autoref_rules]: assumes "GEN_OP es_impl {} (\R\Rs)" assumes "GEN_OP un_impl (\) (\R\Rs\\R\Rs\\R\Rs)" shows "(\i A. RETURN (Un_set_drop_tr es_impl un_impl i A),Un_set_drop_impl) \nat_rel \ \\R\Rs\as_rel \ \\R\Rs\nres_rel" apply (intro fun_relI nres_relI) apply (rule order_trans[OF Un_set_drop_tr.refine]) using Un_set_drop_code.refine[of es_impl Rs R un_impl, param_fo, THEN nres_relD] using assms by simp subsubsection \Actual Refinement\ type_synonym 'Q gGS = "nat set list \ 'Q GS" type_synonym 'Q goGS = "'Q ce \ 'Q oGS" context igb_graph begin definition gGS_invar :: "'Q gGS \ bool" where "gGS_invar s \ let (a,S,B,I,P) = s in GS_invar (S,B,I,P) \ length a = length B \ \(set a) \ {0.. :: "'Q gGS \ 'Q abs_gstate" where "gGS_\ s \ let (a,s)=s in (a,GS.\ s)" definition "gGS_rel \ br gGS_\ gGS_invar" lemma gGS_rel_sv[relator_props,intro!,simp]: "single_valued gGS_rel" unfolding gGS_rel_def by auto definition goGS_invar :: "'Q goGS \ bool" where "goGS_invar s \ let (brk,ogs)=s in brk=None \ oGS_invar ogs" definition "goGS_\ s \ let (brk,ogs)=s in (brk,oGS_\ ogs)" definition "goGS_rel \ br goGS_\ goGS_invar" lemma goGS_rel_sv[relator_props,intro!,simp]: "single_valued goGS_rel" unfolding goGS_rel_def by auto end context igb_fr_graph begin lemma gGS_relE: assumes "(s',(a,p,D,pE))\gGS_rel" obtains S' B' I' P' where "s'=(a,S',B',I',P')" and "((S',B',I',P'),(p,D,pE))\GS_rel" and "length a = length B'" and "\(set a) \ {0.._def GS.\_def) apply (rule that) apply (simp only:) apply (auto simp: GS_rel_def br_def gGS_invar_def GS.\_def) done definition goinitial_impl :: "'Q goGS" where "goinitial_impl \ (None,Map.empty)" lemma goinitial_impl_refine: "(goinitial_impl,goinitial)\goGS_rel" by (auto simp: goinitial_impl_def goinitial_def goGS_rel_def br_def simp: goGS_\_def goGS_invar_def oGS_\_def oGS_invar_def) definition gto_outer_impl :: "'Q ce \ 'Q gGS \ 'Q goGS" where "gto_outer_impl brk s \ let (A,S,B,I,P)=s in (brk,I)" lemma gto_outer_refine: assumes A: "brk = None \ (p=[] \ pE={})" assumes B: "(s, (A,p, D, pE)) \ gGS_rel" assumes C: "(brk',brk)\Id" shows "(gto_outer_impl brk' s,gto_outer brk (A,p,D,pE))\goGS_rel" proof (cases s) fix A S B I P assume [simp]: "s=(A,S,B,I,P)" show ?thesis using C apply (cases brk) using assms I_to_outer[of S B I P D] apply (auto simp: goGS_rel_def br_def goGS_\_def gto_outer_def gto_outer_impl_def goGS_invar_def simp: gGS_rel_def oGS_rel_def GS_rel_def gGS_\_def gGS_invar_def GS.\_def) [] using B apply (auto simp: gto_outer_def gto_outer_impl_def simp: br_def goGS_rel_def goGS_invar_def goGS_\_def oGS_\_def simp: gGS_rel_def gGS_\_def GS.\_def GS.D_\_def ) done qed definition "gpush_impl v s \ let (a,s)=s in (a@[acc v], push_impl v s)" lemma gpush_impl_refine: assumes B: "(s',(a,p,D,pE))\gGS_rel" assumes A: "(v',v)\Id" assumes PRE: "v' \ \(set p)" "v' \ D" shows "(gpush_impl v' s', gpush v (a,p,D,pE))\gGS_rel" proof - from B obtain S' B' I' P' where [simp]: "s'=(a,S',B',I',P')" and OSR: "((S',B',I',P'),(p,D,pE))\GS_rel" and L: "length a = length B'" and R: "\(set a) \ {0.._def GS_rel_def br_def apply (auto dest: AUX1) done qed definition gpop_impl :: "'Q gGS \ 'Q gGS nres" where "gpop_impl s \ do { let (a,s)=s; s\pop_impl s; ASSERT (a\[]); let a = butlast a; RETURN (a,s) }" lemma gpop_impl_refine: assumes A: "(s',(a,p,D,pE))\gGS_rel" assumes PRE: "p \ []" "pE \ last p \ UNIV = {}" shows "gpop_impl s' \ \gGS_rel (RETURN (gpop (a,p,D,pE)))" proof - from A obtain S' B' I' P' where [simp]: "s'=(a,S',B',I',P')" and OSR: "((S',B',I',P'),(p,D,pE))\GS_rel" and L: "length a = length B'" and R: "\(set a) \ {0..[]" using L by (auto simp add: GS_rel_def br_def GS.\_def GS.p_\_def) { fix S B I P S' B' I' P' assume "nofail (pop_impl ((S, B, I, P)::'a GS))" "inres (pop_impl ((S, B, I, P)::'a GS)) (S', B', I', P')" hence "length B' = length B - Suc 0" apply (simp add: pop_impl_def GS.pop_impl_def Let_def refine_pw_simps) apply auto done } note AUX1=this from A L show ?thesis unfolding gpop_impl_def gpop_def gGS_rel_def gGS_\_def br_def apply (simp add: Let_def) using pop_refine[OF OSR PRE] apply (simp add: pw_le_iff refine_pw_simps split: prod.splits) unfolding gGS_rel_def gGS_invar_def gGS_\_def GS_rel_def GS.\_def br_def apply (auto dest!: AUX1 in_set_butlastD iff: Sup_le_iff) done qed definition gselect_edge_impl :: "'Q gGS \ ('Q option \ 'Q gGS) nres" where "gselect_edge_impl s \ do { let (a,s)=s; (vo,s)\select_edge_impl s; RETURN (vo,a,s) }" thm select_edge_refine lemma gselect_edge_impl_refine: assumes A: "(s', a, p, D, pE) \ gGS_rel" assumes PRE: "p \ []" shows "gselect_edge_impl s' \ \(Id \\<^sub>r gGS_rel) (gselect_edge (a, p, D, pE))" proof - from A obtain S' B' I' P' where [simp]: "s'=(a,S',B',I',P')" and OSR: "((S',B',I',P'),(p,D,pE))\GS_rel" and L: "length a = length B'" and R: "\(set a) \ {0.._def gGS_invar_def GS_rel_def GS.\_def apply (simp split: prod.splits) apply clarsimp using R apply (auto simp: L dest: AUX1) done qed term GS.idx_of_impl thm GS_invar.idx_of_correct definition gcollapse_impl_aux :: "'Q \ 'Q gGS \ 'Q gGS nres" where "gcollapse_impl_aux v s \ do { let (A,s)=s; \<^cancel>\ASSERT (v\\set (GS.p_\ s));\ i \ GS.idx_of_impl s v; s \ collapse_impl v s; ASSERT (i < length A); us \ Un_set_drop_impl i A; let A = take i A @ [us]; RETURN (A,s) }" term collapse lemma gcollapse_alt: "gcollapse v APDPE = ( let (a,p,D,pE)=APDPE; i=idx_of p v; s=collapse v (p,D,pE); us=\(set (drop i a)); a = take i a @ [us] in (a,s))" unfolding gcollapse_def gcollapse_aux_def collapse_def collapse_aux_def by auto thm collapse_refine lemma gcollapse_impl_aux_refine: assumes A: "(s', a, p, D, pE) \ gGS_rel" assumes B: "(v',v)\Id" assumes PRE: "v\\(set p)" shows "gcollapse_impl_aux v' s' \ \ gGS_rel (RETURN (gcollapse v (a, p, D, pE)))" proof - note [simp] = Let_def from A obtain S' B' I' P' where [simp]: "s'=(a,S',B',I',P')" and OSR: "((S',B',I',P'),(p,D,pE))\GS_rel" and L: "length a = length B'" and R: "\(set a) \ {0.. (S',B',I',P') = p" by (simp add: GS_rel_def br_def GS.\_def) from OSR PRE have PRE': "v \ \(set (GS.p_\ (S',B',I',P')))" by (simp add: GS_rel_def br_def GS.\_def) from OSR have GS_invar: "GS_invar (S',B',I',P')" by (simp add: GS_rel_def br_def) term GS.B { fix s assume "collapse v (p, D, pE) = (GS.p_\ s, GS.D_\ s, GS.pE_\ s)" hence "length (GS.B s) = Suc (idx_of p v)" unfolding collapse_def collapse_aux_def Let_def apply (cases s) apply (auto simp: GS.p_\_def) apply (drule arg_cong[where f=length]) using GS_invar.p_\_disjoint_sym[OF GS_invar] and PRE \GS.p_\ (S', B', I', P') = p\ idx_of_props(1)[of p v] by simp } note AUX1 = this show ?thesis unfolding gcollapse_alt gcollapse_impl_aux_def apply simp apply (rule RETURN_as_SPEC_refine) apply (refine_rcg order_trans[OF GS_invar.idx_of_correct[OF GS_invar PRE']] order_trans[OF collapse_refine[OF OSR B PRE, simplified]] refine_vcg ) using PRE' apply simp apply (simp add: L) using Un_set_drop_impl_correct acc_bound R apply (simp add: refine_pw_simps pw_le_iff) unfolding gGS_rel_def GS_rel_def GS.\_def br_def gGS_\_def gGS_invar_def apply (clarsimp simp: L dest!: AUX1) apply (auto dest!: AUX1 simp: L) apply (force dest!: in_set_dropD) [] apply (force dest!: in_set_takeD) [] done qed definition gcollapse_impl :: "'Q \ 'Q gGS \ 'Q gGS nres" where "gcollapse_impl v s \ do { let (A,S,B,I,P)=s; i \ GS.idx_of_impl (S,B,I,P) v; ASSERT (i+1 \ length B); let B = take (i+1) B; ASSERT (i < length A); us\Un_set_drop_impl i A; let A = take i A @ [us]; RETURN (A,S,B,I,P) }" lemma gcollapse_impl_aux_opt_refine: "gcollapse_impl v s \ gcollapse_impl_aux v s" unfolding gcollapse_impl_def gcollapse_impl_aux_def collapse_impl_def GS.collapse_impl_def apply (simp add: refine_pw_simps pw_le_iff split: prod.splits) apply blast done lemma gcollapse_impl_refine: assumes A: "(s', a, p, D, pE) \ gGS_rel" assumes B: "(v',v)\Id" assumes PRE: "v\\(set p)" shows "gcollapse_impl v' s' \ \ gGS_rel (RETURN (gcollapse v (a, p, D, pE)))" using order_trans[OF gcollapse_impl_aux_opt_refine gcollapse_impl_aux_refine[OF assms]] . definition ginitial_impl :: "'Q \ 'Q goGS \ 'Q gGS" where "ginitial_impl v0 s0 \ ([acc v0],initial_impl v0 (snd s0))" lemma ginitial_impl_refine: assumes A: "v0\goD s0" "go_is_no_brk s0" assumes REL: "(s0i,s0)\goGS_rel" "(v0i,v0)\Id" shows "(ginitial_impl v0i s0i,ginitial v0 s0)\gGS_rel" unfolding ginitial_impl_def ginitial_def using REL initial_refine[OF A(1) _ REL(2), of "snd s0i"] A(2) apply (auto simp: gGS_rel_def br_def gGS_\_def gGS_invar_def goGS_rel_def goGS_\_def simp: go_is_no_brk_def goD_def oGS_rel_def GS_rel_def goGS_invar_def split: prod.splits ) using acc_bound apply (fastforce simp: initial_impl_def GS_initial_impl_def)+ done definition gpath_is_empty_impl :: "'Q gGS \ bool" where "gpath_is_empty_impl s = path_is_empty_impl (snd s)" lemma gpath_is_empty_refine: "(s,(a,p,D,pE))\gGS_rel \ gpath_is_empty_impl s \ p=[]" unfolding gpath_is_empty_impl_def using path_is_empty_refine by (fastforce simp: gGS_rel_def br_def gGS_invar_def gGS_\_def GS.\_def) definition gis_on_stack_impl :: "'Q \ 'Q gGS \ bool" where "gis_on_stack_impl v s = is_on_stack_impl v (snd s)" lemma gis_on_stack_refine: "\(s,(a,p,D,pE))\gGS_rel\ \ gis_on_stack_impl v s \ v\\(set p)" unfolding gis_on_stack_impl_def using is_on_stack_refine by (fastforce simp: gGS_rel_def br_def gGS_invar_def gGS_\_def GS.\_def) definition gis_done_impl :: "'Q \ 'Q gGS \ bool" where "gis_done_impl v s \ is_done_impl v (snd s)" thm is_done_refine lemma gis_done_refine: "(s,(a,p,D,pE))\gGS_rel \ gis_done_impl v s \ (v \ D)" using is_done_refine[of "(snd s)" v] by (auto simp: gGS_rel_def br_def gGS_\_def gGS_invar_def GS.\_def gis_done_impl_def) definition (in -) "on_stack_less I u v \ case I v of Some (STACK j) \ j False" definition (in -) "on_stack_ge I l v \ case I v of Some (STACK j) \ l\j | _ \ False" lemma (in GS_invar) set_butlast_p_refine: assumes PRE: "p_\\[]" shows "Collect (on_stack_less I (last B)) = \(set (butlast p_\))" (is "?L=?R") proof (intro equalityI subsetI) from PRE have [simp]: "B\[]" by (auto simp: p_\_def) have [simp]: "S\[]" by (simp add: empty_eq) { fix v assume "v\?L" then obtain j where [simp]: "I v = Some (STACK j)" and "jj have "jj] find_seg_correct[OF \j] have "v\seg (find_seg j)" "find_seg j < length B" by auto moreover with \j have "find_seg j < length B - 1" (* What follows is an unreadable, auto-generated structured proof that replaces the following smt-call: by (smt GS.seg_start_def `seg_start (find_seg j) \ j`)*) proof - have f1: "\x\<^sub>1 x. \ (x\<^sub>1::nat) < x\<^sub>1 - x" using less_imp_diff_less by blast have "j \ last B" by (metis \j < last B\ less_le) hence f2: "\x\<^sub>1. \ last B < x\<^sub>1 \ \ x\<^sub>1 \ j" using f1 by (metis diff_diff_cancel le_trans) have "\x\<^sub>1. seg_end x\<^sub>1 \ j \ \ x\<^sub>1 < find_seg j" by (metis \seg_start (find_seg j) \ j\ calculation(2) le_trans seg_end_less_start) thus "find_seg j < length B - 1" using f1 f2 by (metis GS.seg_start_def \B \ []\ \j < B ! (length B - 1)\ \seg_start (find_seg j) \ j\ calculation(2) diff_diff_cancel last_conv_nth nat_neq_iff seg_start_less_end) qed ultimately show "v\?R" by (auto simp: p_\_def map_butlast[symmetric] butlast_upt) } { fix v assume "v\?R" then obtain i where "iseg i" by (auto simp: p_\_def map_butlast[symmetric] butlast_upt) then obtain j where "j < seg_end i" and "v=S!j" by (auto simp: seg_def) hence "j length B - 1" using \i by (auto simp: seg_end_def last_conv_nth split: if_split_asm) with sorted_nth_mono[OF B_sorted \i+1 \ length B - 1\] have "jj < seg_end i\ have "ji + 1 \ length B - 1\ add_lessD1 less_imp_diff_less less_le_not_le nat_neq_iff seg_end_bound) (*by (smt `i < length B - 1` seg_end_bound)*) with I_consistent \v=S!j\ have "I v = Some (STACK j)" by auto ultimately show "v\?L" by (auto simp: on_stack_less_def) } qed lemma (in GS_invar) set_last_p_refine: assumes PRE: "p_\\[]" shows "Collect (on_stack_ge I (last B)) = last p_\" (is "?L=?R") proof (intro equalityI subsetI) from PRE have [simp]: "B\[]" by (auto simp: p_\_def) have [simp]: "S\[]" by (simp add: empty_eq) { fix v assume "v\?L" then obtain j where [simp]: "I v = Some (STACK j)" and "j\last B" by (auto simp: on_stack_ge_def split: option.splits node_state.splits) from I_consistent[of v j] have [simp]: "jseg (length B - 1)" using \j\last B\ by (auto simp: seg_def last_conv_nth seg_start_def seg_end_def) thus "v\last p_\" by (auto simp: p_\_def last_map) } { fix v assume "v\?R" hence "v\seg (length B - 1)" by (auto simp: p_\_def last_map) then obtain j where "v=S!j" "j\last B" "jj\last B\ show "v\?L" by (auto simp: on_stack_ge_def) } qed definition ce_impl :: "'Q gGS \ (('Q set \ 'Q set) option \ 'Q gGS) nres" where "ce_impl s \ do { let (a,S,B,I,P) = s; ASSERT (B\[]); let bls = Collect (on_stack_less I (last B)); let ls = Collect (on_stack_ge I (last B)); RETURN (Some (bls, ls),a,S,B,I,P) }" lemma ce_impl_refine: assumes A: "(s,(a,p,D,pE))\gGS_rel" assumes PRE: "p\[]" shows "ce_impl s \ \(Id\\<^sub>rgGS_rel) (RETURN (Some (\(set (butlast p)),last p),a,p,D,pE))" proof - from A obtain S' B' I' P' where [simp]: "s=(a,S',B',I',P')" and OSR: "((S',B',I',P'),(p,D,pE))\GS_rel" and L: "length a = length B'" by (rule gGS_relE) from OSR have [simp]: "GS.p_\ (S',B',I',P') = p" by (simp add: GS_rel_def br_def GS.\_def) from PRE have NE': "GS.p_\ (S', B', I', P') \ []" by simp hence BNE[simp]: "B'\[]" by (simp add: GS.p_\_def) from OSR have GS_invar: "GS_invar (S',B',I',P')" by (simp add: GS_rel_def br_def) show ?thesis using GS_invar.set_butlast_p_refine[OF GS_invar NE'] using GS_invar.set_last_p_refine[OF GS_invar NE'] unfolding ce_impl_def using A by auto qed definition "last_is_acc_impl s \ do { let (a,_)=s; ASSERT (a\[]); RETURN (\ilast a) }" lemma last_is_acc_impl_refine: assumes A: "(s,(a,p,D,pE))\gGS_rel" assumes PRE: "a\[]" shows "last_is_acc_impl s \ RETURN (last a = {0.. {0.._def by auto hence C: "(\ilast a) \ (last a = {0.._def br_def split: prod.splits) show ?thesis unfolding last_is_acc_impl_def by (auto simp: gGS_rel_def br_def gGS_\_def C PRE split: prod.splits) qed definition go_is_no_brk_impl :: "'Q goGS \ bool" where "go_is_no_brk_impl s \ fst s = None" lemma go_is_no_brk_refine: "(s,s')\goGS_rel \ go_is_no_brk_impl s \ go_is_no_brk s'" unfolding go_is_no_brk_def go_is_no_brk_impl_def by (auto simp: goGS_rel_def br_def goGS_\_def split: prod.splits) definition goD_impl :: "'Q goGS \ 'Q oGS" where "goD_impl s \ snd s" lemma goD_refine: "go_is_no_brk s' \ (s,s')\goGS_rel \ (goD_impl s, goD s')\oGS_rel" unfolding goD_impl_def goD_def by (auto simp: goGS_rel_def br_def goGS_\_def goGS_invar_def oGS_rel_def go_is_no_brk_def) definition go_is_done_impl :: "'Q \ 'Q goGS \ bool" where "go_is_done_impl v s \ is_done_oimpl v (snd s)" thm is_done_orefine lemma go_is_done_impl_refine: "\go_is_no_brk s'; (s,s')\goGS_rel; (v,v')\Id\ \ go_is_done_impl v s \ (v'\goD s')" using is_done_orefine unfolding go_is_done_impl_def goD_def go_is_no_brk_def apply (fastforce simp: goGS_rel_def br_def goGS_invar_def goGS_\_def) done definition goBrk_impl :: "'Q goGS \ 'Q ce" where "goBrk_impl \ fst" lemma goBrk_refine: "(s,s')\goGS_rel \ (goBrk_impl s, goBrk s')\Id" unfolding goBrk_impl_def goBrk_def by (auto simp: goGS_rel_def br_def goGS_\_def split: prod.splits) definition find_ce_impl :: "('Q set \ 'Q set) option nres" where "find_ce_impl \ do { stat_start_nres; let os=goinitial_impl; os\FOREACHci (\it os. fgl_outer_invar it (goGS_\ os)) V0 (go_is_no_brk_impl) (\v0 s0. do { if \go_is_done_impl v0 s0 then do { let s = (None,ginitial_impl v0 s0); (brk,s)\WHILEIT (\(brk,s). fgl_invar v0 (oGS_\ (goD_impl s0)) (brk,snd (gGS_\ s))) (\(brk,s). brk=None \ \gpath_is_empty_impl s) (\(l,s). do { \ \Select edge from end of path\ (vo,s) \ gselect_edge_impl s; case vo of Some v \ do { if gis_on_stack_impl v s then do { s\gcollapse_impl v s; b\last_is_acc_impl s; if b then ce_impl s else RETURN (None,s) } else if \gis_done_impl v s then do { \ \Edge to new node. Append to path\ RETURN (None,gpush_impl v s) } else do { \ \Edge to done node. Skip\ RETURN (None,s) } } | None \ do { \ \No more outgoing edges from current node on path\ s\gpop_impl s; RETURN (None,s) } }) (s); RETURN (gto_outer_impl brk s) } else RETURN s0 }) os; stat_stop_nres; RETURN (goBrk_impl os) }" lemma find_ce_impl_refine: "find_ce_impl \ \Id gfind_ce" proof - note [refine2] = prod_relI[OF IdI[of None] ginitial_impl_refine] have [refine]: "\s a p D pE. \ (s,(a,p,D,pE))\gGS_rel; p \ []; pE \ last p \ UNIV = {} \ \ gpop_impl s \ (\s. RETURN (None, s)) \ SPEC (\c. (c, None, gpop (a,p,D,pE)) \ Id \\<^sub>r gGS_rel)" apply (drule (2) gpop_impl_refine) apply (fastforce simp add: pw_le_iff refine_pw_simps) done note [[goals_limit = 1]] note FOREACHci_refine_rcg'[refine del] show ?thesis unfolding find_ce_impl_def gfind_ce_def apply (refine_rcg bind_refine' prod_relI IdI inj_on_id gselect_edge_impl_refine gpush_impl_refine oinitial_refine ginitial_impl_refine bind_Let_refine2[OF gcollapse_impl_refine] if_bind_cond_refine[OF last_is_acc_impl_refine] ce_impl_refine goinitial_impl_refine gto_outer_refine goBrk_refine FOREACHci_refine_rcg'[where R=goGS_rel, OF inj_on_id] ) apply refine_dref_type apply (simp_all add: go_is_no_brk_refine go_is_done_impl_refine) apply (auto simp: goGS_rel_def br_def) [] apply (auto simp: goGS_rel_def br_def goGS_\_def gGS_\_def gGS_rel_def goD_def goD_impl_def) [] apply (auto dest: gpath_is_empty_refine ) [] apply (auto dest: gis_on_stack_refine) [] apply (auto dest: gis_done_refine) [] done qed end section \Constructing a Lasso from Counterexample\ subsection \Lassos in GBAs\ context igb_fr_graph begin definition reconstruct_reach :: "'Q set \ 'Q set \ ('Q list \ 'Q) nres" \ \Reconstruct the reaching path of a lasso\ where "reconstruct_reach Vr Vl \ do { res \ find_path (E\Vr\UNIV) V0 (\v. v\Vl); ASSERT (res \ None); RETURN (the res) }" lemma reconstruct_reach_correct: assumes CEC: "ce_correct Vr Vl" shows "reconstruct_reach Vr Vl \ SPEC (\(pr,va). \v0\V0. path E v0 pr va \ va\Vl)" proof - have FIN_aux: "finite ((E \ Vr \ UNIV)\<^sup>* `` V0)" by (metis finite_reachableE_V0 finite_subset inf_sup_ord(1) inf_sup_ord(2) inf_top.left_neutral reachable_mono) { fix u p v assume P: "path E u p v" and SS: "set p \ Vr" have "path (E \ Vr\UNIV) u p v" apply (rule path_mono[OF _ path_restrict[OF P]]) using SS by auto } note P_CONV=this from CEC obtain v0 "pr" va where "v0\V0" "set pr \ Vr" "va\Vl" "path (E \ Vr\UNIV) v0 pr va" unfolding ce_correct_def is_lasso_prpl_def is_lasso_prpl_pre_def by (force simp: neq_Nil_conv path_simps dest: P_CONV) hence 1: "va \ (E \ Vr \ UNIV)\<^sup>* `` V0" by (auto dest: path_is_rtrancl) show ?thesis using assms unfolding reconstruct_reach_def apply (refine_rcg refine_vcg order_trans[OF find_path_ex_rule]) apply (clarsimp_all simp: FIN_aux finite_V0) using \va\Vl\ 1 apply auto [] apply (auto dest: path_mono[of "E \ Vr \ UNIV" E, simplified]) [] done qed definition "rec_loop_invar Vl va s \ let (v,p,cS) = s in va \ E\<^sup>*``V0 \ path E va p v \ cS = acc v \ (\(acc`set p)) \ va \ Vl \ v \ Vl \ set p \ Vl" definition reconstruct_lasso :: "'Q set \ 'Q set \ ('Q list \ 'Q list) nres" \ \Reconstruct lasso\ where "reconstruct_lasso Vr Vl \ do { (pr,va) \ reconstruct_reach Vr Vl; let cS_full = {0.. UNIV\Vl; (vd,p,_) \ WHILEIT (rec_loop_invar Vl va) (\(_,_,cS). cS \ cS_full) (\(v,p,cS). do { ASSERT (\v'. (v,v')\E\<^sup>* \ \ (acc v' \ cS)); sr \ find_path E {v} (\v. \ (acc v \ cS)); ASSERT (sr \ None); let (p_seg,v) = the sr; RETURN (v,p@p_seg,cS \ acc v) }) (va,[],acc va); p_close_r \ (if p=[] then find_path1 E vd ((=) va) else find_path E {vd} ((=) va)); ASSERT (p_close_r \ None); let (p_close,_) = the p_close_r; RETURN (pr, p@p_close) }" lemma (in igb_fr_graph) reconstruct_lasso_correct: assumes CEC: "ce_correct Vr Vl" shows "reconstruct_lasso Vr Vl \ SPEC (is_lasso_prpl)" proof - let ?E = "E \ UNIV \ Vl" have E_SS: "E \ Vl \ Vl \ ?E" by auto from CEC have REACH: "Vl \ E\<^sup>*``V0" and CONN: "Vl\Vl \ (E \ Vl\Vl)\<^sup>*" and NONTRIV: "Vl\Vl \ E \ {}" and NES[simp]: "Vl\{}" and ALL: "\(acc`Vl) = {0..(_::'Q,_::'Q list,cS). cS))" hence WF: "wf term_rel" by simp { fix va assume "va \ Vl" hence "rec_loop_invar Vl va (va, [], acc va)" unfolding rec_loop_invar_def using REACH by auto } note INVAR_INITIAL = this { fix v p cS va assume "rec_loop_invar Vl va (v, p, cS)" hence "finite ((?E)\<^sup>* `` {v})" apply - apply (rule finite_subset[where B="E\<^sup>*``V0"]) unfolding rec_loop_invar_def using REACH apply (clarsimp_all dest!: path_is_rtrancl) apply (drule rtrancl_mono_mp[where U="?E" and V=E, rotated], (auto) []) by (metis rev_ImageI rtrancl_trans) } note FIN1 = this { fix va v :: 'Q and p cS assume INV: "rec_loop_invar Vl va (v,p,cS)" and NC: "cS \ {0..cS" unfolding rec_loop_invar_def by auto blast - with ALL obtain v' where "v'\Vl" "\ acc v' \ cS" - by simp (smt UN_iff atLeastLessThan_iff le0 subsetCE) + with ALL obtain v' where v': "v'\Vl" "\ acc v' \ cS" + by (metis NES atLeastLessThan_iff cSUP_least in_mono zero_le) - moreover with CONN INV have "(v,v')\(E \ Vl \ Vl)\<^sup>*" + with CONN INV have "(v,v')\(E \ Vl \ Vl)\<^sup>*" unfolding rec_loop_invar_def by auto hence "(v,v')\?E\<^sup>*" using rtrancl_mono_mp[OF E_SS] by blast - ultimately have "\v'. (v,v')\(?E)\<^sup>* \ \ acc v' \ cS" by auto + with v' have "\v'. (v,v')\(?E)\<^sup>* \ \ acc v' \ cS" by auto } note ASSERT1 = this { fix va v p cS v' p' assume "rec_loop_invar Vl va (v, p, cS)" and "path (?E) v p' v'" and "\ (acc v' \ cS)" and "\v\set p'. acc v \ cS" hence "rec_loop_invar Vl va (v', p@p', cS \ acc v')" unfolding rec_loop_invar_def apply simp apply (intro conjI) apply (auto simp: path_simps dest: path_mono[of "?E" E, simplified]) [] apply (cases p') apply (auto simp: path_simps) [2] apply (cases p' rule: rev_cases) apply (auto simp: path_simps) [2] apply (erule path_set_induct) apply auto [2] done } note INV_PRES = this { fix va v p cS v' p' assume "rec_loop_invar Vl va (v, p, cS)" and "path ?E v p' v'" and "\ (acc v' \ cS)" and "\v\set p'. acc v \ cS" hence "((v', p@p', cS \ acc v'), (v,p,cS)) \ term_rel" unfolding term_rel_def rec_loop_invar_def by (auto simp: finite_psupset_def) } note VAR = this have CONN1: "Vl \ Vl \ (?E)\<^sup>+" proof clarify fix a b assume "a\Vl" "b\Vl" from NONTRIV obtain u v where E: "(u,v)\(E \ Vl\Vl)" by auto from CONN \a\Vl\ E have "(a,u)\(E\Vl\Vl)\<^sup>*" by auto also note E also (rtrancl_into_trancl1) from CONN \b\Vl\ E have "(v,b)\(E\Vl\Vl)\<^sup>*" by auto finally show "(a,b)\(?E)\<^sup>+" using trancl_mono[OF _ E_SS] by auto qed { fix va v p cS assume "rec_loop_invar Vl va (v, p, cS)" hence "(v,va) \ (?E)\<^sup>+" unfolding rec_loop_invar_def using CONN1 by auto } note CLOSE1 = this { fix va v p cS assume "rec_loop_invar Vl va (v, p, cS)" hence "(v,va) \ (?E)\<^sup>*" unfolding rec_loop_invar_def using CONN rtrancl_mono[OF E_SS] by auto } note CLOSE2 = this { fix "pr" vd pl va v0 assume "rec_loop_invar Vl va (vd, [], {0.. Vl" "v0 \ V0" "path E v0 pr va" "pl \ []" "path ?E vd pl va" hence "is_lasso_prpl (pr, pl)" unfolding is_lasso_prpl_def is_lasso_prpl_pre_def rec_loop_invar_def by (auto simp: neq_Nil_conv path_simps dest!: path_mono[of "?E" E, simplified]) [] } note INV_POST1 = this { fix va v p p' "pr" v0 assume INV: "rec_loop_invar Vl va (v,p,{0..[]" "path ?E v p' va" and PR: "v0\V0" "path E v0 pr va" from INV have "\iq\insert v (set p). i \ acc q" unfolding rec_loop_invar_def by auto moreover from INV 1 have "insert v (set p) \ set p \ set p'" unfolding rec_loop_invar_def apply (cases p) apply blast apply (cases p') apply (auto simp: path_simps) done ultimately have ACC: "\iq\set p \ set p'. i \ acc q" by blast from INV 1 have PL: "path E va (p @ p') va" by (auto simp: rec_loop_invar_def path_simps dest!: path_mono[of "?E" E, simplified]) [] have "is_lasso_prpl (pr,p@p')" unfolding is_lasso_prpl_def is_lasso_prpl_pre_def apply (clarsimp simp: ACC) using PR PL \p\[]\ by auto } note INV_POST2 = this show ?thesis unfolding reconstruct_lasso_def apply (refine_rcg WF order_trans[OF reconstruct_reach_correct] order_trans[OF find_path_ex_rule] order_trans[OF find_path1_ex_rule] refine_vcg ) apply (vc_solve del: subsetI solve: ASSERT1 INV_PRES asm_rl VAR CLOSE1 CLOSE2 INV_POST1 INV_POST2 simp: INVAR_INITIAL FIN1 CEC) done qed definition find_lasso where "find_lasso \ do { ce \ find_ce_spec; case ce of None \ RETURN None | Some (Vr,Vl) \ do { l \ reconstruct_lasso Vr Vl; RETURN (Some l) } }" lemma (in igb_fr_graph) find_lasso_correct: "find_lasso \ find_lasso_spec" unfolding find_lasso_spec_def find_lasso_def find_ce_spec_def apply (refine_rcg refine_vcg order_trans[OF reconstruct_lasso_correct]) apply auto done end end diff --git a/thys/No_FTL_observers/Axioms.thy b/thys/No_FTL_observers/Axioms.thy --- a/thys/No_FTL_observers/Axioms.thy +++ b/thys/No_FTL_observers/Axioms.thy @@ -1,266 +1,266 @@ (* Author: Mike Stannett Date: 22 October 2012 m.stannett@sheffield.ac.uk *) theory Axioms imports SpaceTime SomeFunc begin record Body = Ph :: "bool" IOb :: "bool" class WorldView = SpaceTime + fixes (* Worldview relation *) W :: "Body \ Body \ 'a Point \ bool" ("_ sees _ at _") and (* Worldview transformation *) wvt :: "Body \ Body \ 'a Point \ 'a Point" assumes AxWVT: "\ IOb m; IOb k \ \ (W k b x \ W m b (wvt m k x))" and AxWVTSym: "\ IOb m; IOb k \ \ (y = wvt k m x \ x = wvt m k y)" begin end (* THE BASIC AXIOMS *) (* ================ *) class AxiomPreds = WorldView begin fun sqrtTest :: "'a \ 'a \ bool" where "sqrtTest x r = ((r \ 0) \ (r*r = x))" fun cTest :: "Body \ 'a \ bool" where "cTest m v = ( (v > 0) \ ( \x y . ( (\p. (Ph p \ W m p x \ W m p y)) \ (space2 x y = (v * v)*(time2 x y)) )))" end (* AxEuclidean Quantities form a Euclidean field, ie positive quantities have square roots. We introduce a function, sqrt, that determines them. *) class AxEuclidean = AxiomPreds + Quantities + assumes AxEuclidean: "(x \ Groups.zero_class.zero) \ (\r. sqrtTest x r)" begin abbreviation sqrt :: "'a \ 'a" where "sqrt \ someFunc sqrtTest" lemma lemSqrt: assumes "x \ 0" and "r = sqrt x" shows "r \ 0 \ r*r = x" proof - have rootExists: "(\r. sqrtTest x r)" by (metis AxEuclidean assms(1)) hence "sqrtTest x (sqrt x)" by (metis lemSomeFunc) thus ?thesis using assms(2) by simp qed end (* AxLight There is an inertial observer, according to whom, any light signal moves with the same velocity in any direction *) class AxLight = WorldView + assumes AxLight: "\m v.( IOb m \ (v > (0::'a)) \ ( \x y.( (\p.(Ph p \ W m p x \ W m p y)) \ (space2 x y = (v * v)*time2 x y) )))" begin end (* AxPh For any inertial observer, the speed of light is the same in every direction everywhere, and it is finite. Furthermore, it is possible to send out a light signal in any direction. *) class AxPh = WorldView + AxiomPreds + assumes AxPh: "IOb m \ (\v. cTest m v)" begin abbreviation c :: "Body \ 'a" where "c \ someFunc cTest" fun lightcone :: "Body \ 'a Point \ 'a Cone" where "lightcone m v = mkCone v (c m)" lemma lemCProps: assumes "IOb m" and "v = c m" shows "(v > 0) \ (\x y.((\p. (Ph p \ W m p x \ W m p y)) \ ( space2 x y = (c m * c m)*time2 x y )))" proof - have vExists: "(\v. cTest m v)" by (metis AxPh assms(1)) hence "cTest m (c m)" by (metis lemSomeFunc) thus ?thesis using assms(2) by simp qed lemma lemCCone: assumes "IOb m" and "onCone y (lightcone m x)" shows "\p. (Ph p \ W m p x \ W m p y)" proof - have "(\p.(Ph p \ W m p x \ W m p y)) \ ( space2 x y = (c m * c m)*time2 x y )" - by (smt assms(1) lemCProps) + by (simp add: assms(1) lemCProps) hence ph_exists: "(space2 x y = (c m * c m)*time2 x y) \ (\p.(Ph p \ W m p x \ W m p y))" by metis define lcmx where "lcmx = lightcone m x" have lcmx_vertex: "vertex lcmx = x" by (simp add: lcmx_def) have lcmx_slope: "slope lcmx = c m" by (simp add: lcmx_def) have "onCone y lcmx \ (space2 x y = (c m * c m)*time2 x y)" by (metis lcmx_vertex lcmx_slope onCone.simps) hence "space2 x y = (c m * c m)*time2 x y" by (metis lcmx_def assms(2)) thus ?thesis by (metis ph_exists) qed lemma lemCPos: assumes "IOb m" shows "c m > 0" by (metis assms(1) lemCProps) lemma lemCPhoton: assumes "IOb m" shows "\x y. (\p. (Ph p \ W m p x \ W m p y)) \ (space2 x y = (c m * c m)*(time2 x y))" by (metis assms(1) lemCProps) end (* AxEv Inertial observers see the same events (meetings of bodies). This also enables us to discuss the worldview transformation. *) class AxEv = WorldView + assumes AxEv: "\ IOb m; IOb k\ \ (\y. (\b. (W m b x \ W k b y)))" begin end (* Inertial observers can move with any speed slower than that of light *) class AxThExp = WorldView + AxPh + assumes AxThExp: "IOb m \ (\x y .( (\k.(IOb k \ W m k x \ W m k y)) \ (space2 x y < (c m * c m) * time2 x y) ))" begin end (* Every inertial observer is stationary according to himself *) class AxSelf = WorldView + assumes AxSelf: "IOb m \ (W m m x) \ (onAxisT x)" begin end (* All inertial observers agree that the speed of light is 1 *) class AxC = WorldView + AxPh + assumes AxC: "IOb m \ c m = 1" begin end (* Inertial observers agree as to the spatial distance between two events if these two events are simultaneous for both of them. *) class AxSym = WorldView + assumes AxSym: "\ IOb m; IOb k \ \ (W m e x \ W m f y \ W k e x'\ W k f y' \ tval x = tval y \ tval x' = tval y' ) \ (space2 x y = space2 x' y')" begin end (* AxLines All observers agree about lines *) class AxLines = WorldView + assumes AxLines: "\ IOb m; IOb k; collinear x p q \ \ collinear (wvt k m x) (wvt k m p) (wvt k m q)" begin end (* AxPlanes All observers agree about planes *) class AxPlanes = WorldView + assumes AxPlanes: "\ IOb m; IOb k \ \ (coplanar e x y z \ coplanar (wvt k m e) (wvt k m x) (wvt k m y) (wvt k m z))" begin end (* AxCones All observers agree about lightcones *) class AxCones = WorldView + AxPh + assumes AxCones: "\ IOb m; IOb k \ \ ( onCone x (lightCone m v) \ onCone (wvt k m x) (lightcone k (wvt k m v)))" begin end (* All inertial observers see time travelling in the same direction. That is, if m thinks that k reached y after he reached x, then k should also think that he reached y after he reached x. *) class AxTime = WorldView + assumes AxTime: "\ IOb m; IOb k \ \( x \ y \ wvt k m x \ wvt k m y )" begin end end diff --git a/thys/X86_Semantics/Memory.thy b/thys/X86_Semantics/Memory.thy --- a/thys/X86_Semantics/Memory.thy +++ b/thys/X86_Semantics/Memory.thy @@ -1,358 +1,361 @@ (* Title: X86 instruction semantics and basic block symbolic execution Authors: Freek Verbeek, Abhijith Bharadwaj, Joshua Bockenek, Ian Roessle, Timmy Weerwag, Binoy Ravindran Year: 2020 Maintainer: Freek Verbeek (freek@vt.edu) *) section "Memory-related theorems" theory Memory imports BitByte begin context fixes dummy_type :: "'a::len" begin primrec read_bytes :: "('a word \ 8 word) \ 'a word \ nat \ 8word list" where "read_bytes m a 0 = []" | "read_bytes m a (Suc n) = m (a + of_nat n) # read_bytes m a n" text \Read bytes from memory. Memory is represented by a term of @{typ "64 word \ 8 word"}. Given an address @{term [show_types] "a::64 word"} and a size @{term n}, retrieve the bytes in the order they are stored in memory.\ definition region_addresses :: "'a word \ nat \ 'a word set" where "region_addresses a si \ {a' . \ i < si . a' = a + of_nat (si - i - 1)}" text \The set of addresses belonging to a region starting at address @{term "a::64 word"} of @{term si} bytes.\ definition region_overflow :: "'a word \ nat \ bool" where "region_overflow a si \ unat a + si \ 2^LENGTH('a)" text \An overflow occurs if the address plus the size is greater equal @{term "2^64"}\ definition enclosed :: "'a word \ nat \ 'a word \ nat \ bool" where "enclosed a' si' a si \ unat a + si < 2^LENGTH('a) \ unat a \ unat a' \ unat a' + si' \ unat a + si" text \A region is enclosed in another if its @{const region_addresses} is a subset of the other.\ definition separate :: "'a word \ nat \ 'a word \ nat \ bool" where "separate a si a' si' \ si \0 \ si' \ 0 \ region_addresses a si \ region_addresses a' si' = {}" text \A region is separate from another if they do not overlap.\ lemma region_addresses_iff: "a' \ region_addresses a si \ unat (a' - a) < si" apply (auto simp add: region_addresses_def unsigned_of_nat) apply (metis diff_Suc_less le_less_trans less_imp_Suc_add take_bit_nat_less_eq_self zero_less_Suc) - by (smt (z3) add.commute add_Suc_right add_diff_cancel_left' diff_add_cancel less_add_Suc2 less_imp_Suc_add word_unat.Rep_inverse) + by (metis Suc_diff_Suc add.commute diff_add_cancel diff_diff_cancel diff_less less_imp_Suc_add order_less_imp_le word_unat.Rep_inverse zero_less_Suc) lemma notin_region_addresses: assumes "x \ region_addresses a si" shows "unat x < unat a \ unat a + si \ unat x" by (metis assms add.commute less_diff_conv2 not_le_imp_less region_addresses_iff unat_sub_if') lemma notin_region_addresses_sub: assumes "x \ region_addresses a si" shows "unat (x - a') < unat (a - a') \ unat (a - a') + si \ unat (x - a')" using assms notin_region_addresses region_addresses_iff by auto lemma region_addresses_eq_empty_iff: "region_addresses a si = {} \ si = 0" by (metis region_addresses_iff add_diff_cancel_left' ex_in_conv neq0_conv not_less0 unsigned_0) lemma length_read_bytes: shows "length (read_bytes m a si) = si" by (induct si,auto) lemma nth_read_bytes: assumes "n < si" shows "read_bytes m a si ! n = m (a + of_nat (si - 1 - n))" using assms apply (induct si arbitrary: n,auto) subgoal for si n by(cases n,auto) done text \Writing to memory occurs via function @{const override_on}. In case of enclosure, reading bytes from memory overridden on a set of region addresses can be simplified to reading bytes from the overwritten memory only. In case of separation, reading bytes from overridden memory can be simplified to reading from the original memory.\ lemma read_bytes_override_on_enclosed: assumes "offset' \ offset" and "si' \ si" and "unat offset + si' \ si + unat offset'" shows "read_bytes (override_on m m' (region_addresses (a - offset) si)) (a - offset') si' = read_bytes m' (a - offset') si'" proof- { fix i assume 1: "i < si'" let ?i = "(si + i + unat offset') - unat offset - si'" have "i + unat offset' < si' + unat offset" using 1 assms(1) by unat_arith hence 2: "si + i + unat offset' - (unat offset + si') < si" using diff_less[of "(si' + unat offset - i) - unat offset'" si] assms(3) by auto moreover have "of_nat (si' - Suc i) - offset' = of_nat (si - Suc ?i) - offset" using assms 1 2 by (auto simp add: of_nat_diff) ultimately have "\ i' < si. of_nat (si' - Suc i) - offset' = of_nat (si - Suc i') - offset" by auto } note 1 = this show ?thesis apply (rule nth_equalityI) using 1 by (auto simp add: length_read_bytes nth_read_bytes override_on_def region_addresses_def) qed lemmas read_bytes_override_on = read_bytes_override_on_enclosed[where offset=0 and offset'=0,simplified] lemma read_bytes_override_on_enclosed_plus: assumes "unat offset + si' \ si" and "si \ 2^LENGTH('a)" shows "read_bytes (override_on m m' (region_addresses a si)) (offset+a) si' = read_bytes m' (offset+a) si'" proof- { fix i have "i < si' \ \ i' < si. offset + (of_nat (si' - Suc i)::'a word) = of_nat (si - Suc i')" apply (rule exI[of _"si - si' + i - unat offset"]) using assms by (auto simp add: of_nat_diff) } note 1 = this show ?thesis apply (rule nth_equalityI) using assms 1 by (auto simp add: override_on_def length_read_bytes nth_read_bytes region_addresses_def) qed lemma read_bytes_override_on_separate: assumes "separate a si a' si'" shows "read_bytes (override_on m m' (region_addresses a si)) a' si' = read_bytes m a' si'" apply (rule nth_equalityI) using assms by (auto simp add: length_read_bytes nth_read_bytes override_on_def separate_def region_addresses_def) text\Bytes are are written to memory one-by-one, then read by @{const read_bytes} producing a list of bytes. That list is concatenated again using @{const word_rcat}. Writing @{term si} bytes of word @{term w} into memory, reading the byte-list and concatenating again produces @{term si} bytes of the original word.\ lemma word_rcat_read_bytes_enclosed: fixes w :: "'b::len word" assumes "LENGTH('b) \ 2^LENGTH('a)" and "unat offset + si \ 2^LENGTH('a)" shows "word_rcat (read_bytes (\a'. take_byte (unat (a' - a)) w) (a + offset) si) = \unat offset * 8,(unat offset + si) * 8\w" apply (rule word_eqI) using assms apply (auto simp add: test_bit_rcat word_size length_read_bytes rev_nth nth_read_bytes unat_of_nat nth_takebyte unat_word_ariths ) apply (auto simp add: take_byte_def nth_ucast nth_takebits take_bit_eq_mod split: if_split_asm)[1] apply (auto simp add: nth_takebits split: if_split_asm)[1] apply (auto simp add: take_byte_def nth_ucast nth_takebits split: if_split_asm)[1] by (auto simp add: rev_nth length_read_bytes take_byte_def nth_ucast nth_takebits nth_read_bytes unat_word_ariths unat_of_nat take_bit_eq_mod split: if_split_asm) lemmas word_rcat_read_bytes = word_rcat_read_bytes_enclosed[where offset=0,simplified] text \The following theorems allow reasoning over enclosure and separation, for example as linear arithmetic.\ lemma enclosed_spec: assumes enclosed: "enclosed a' si' a si" and x_in: "x \ region_addresses a' si'" shows "x \ region_addresses a si" proof - from x_in have "unat (x - a') < si'" using region_addresses_iff by blast with enclosed have "unat (x - a) < si" unfolding enclosed_def by (auto simp add: unat_sub_if' split: if_split_asm) then show ?thesis using region_addresses_iff by blast qed lemma address_in_enclosed_region_as_linarith: assumes "enclosed a' si' a si" and "x \ region_addresses a' si'" shows "a \ x \ a' \ x \ x < a' + of_nat si' \ x < a + of_nat si" using assms by (auto simp add: enclosed_def region_addresses_def word_le_nat_alt word_less_nat_alt unat_of_nat unat_word_ariths unat_sub_if' take_bit_eq_mod) lemma address_of_enclosed_region_ge: assumes "enclosed a' si' a si" shows "a' \ a" using assms word_le_nat_alt by (auto simp add: enclosed_def) lemma address_in_enclosed_region: assumes "enclosed a' si' a si" and "x \ region_addresses a' si'" shows "unat (x - a) \ unat (a' - a) \ unat (a' - a) + si' > unat (x - a) \ unat (x - a) < si" - by (smt (z3) address_in_enclosed_region_as_linarith add_diff_cancel_left' address_of_enclosed_region_ge assms(1) assms(2) diff_diff_add enclosed_spec le_iff_add nat_add_left_cancel_less region_addresses_iff unat_sub_if' word_le_minus_mono_left word_unat.Rep_inverse word_unat_less_le) + by (smt (verit, ccfv_threshold) Memory.enclosed_def Memory.region_addresses_iff + address_in_enclosed_region_as_linarith assms(1) assms(2) diff_diff_add + le_add_diff_inverse mcs(4) nat_add_left_cancel_less no_ulen_sub of_nat_add + un_ui_le unat_mono unat_of_nat_eq unat_sub unsigned_less word_sub_le_iff) lemma enclosed_minus_minus: fixes a :: "'a word" assumes "offset \ offset'" and "unat offset - si \ unat offset' - si'" and "unat offset' \ si'" and "unat offset \ si" and "a \ offset" shows "enclosed (a - offset') si' (a - offset) si" proof- have "unat offset' \ unat a" using assms(1,5) by unat_arith thus ?thesis using assms apply (auto simp add: enclosed_def unat_sub_if_size word_size) apply unat_arith using diff_le_mono2[of "unat offset - si" "unat offset' - si'" "unat a"] apply (auto simp add: enclosed_def unat_sub_if_size word_size) by unat_arith+ qed lemma enclosed_plus: fixes a :: "'a word" assumes "si' < si" and "unat a + si < 2^LENGTH('a)" shows "enclosed a si' a si" using assms by (auto simp add: enclosed_def) lemma separate_symm: "separate a si a' si' = separate a' si' a si" by (metis inf.commute separate_def) lemma separate_iff: "separate a si a' si' \ si > 0 \ si' > 0 \ unat (a' - a) \ si \ unat (a - a') \ si'" proof assume assm: "separate a si a' si'" have "unat (a' - a) \ si" if "separate a si a' si'" for a si a' si' proof (rule ccontr) assume "\ unat (a' - a) \ si" then have "a' \ region_addresses a si" by (simp add: region_addresses_iff) moreover from that have "a' \ region_addresses a' si'" using region_addresses_iff separate_def by auto ultimately have "\separate a si a' si'" by (meson disjoint_iff separate_def) with that show False by blast qed with assm have "unat (a' - a) \ si" and "unat (a - a') \ si'" using separate_symm by auto with assm show "si > 0 \ si' > 0 \ unat (a' - a) \ si \ unat (a - a') \ si'" using separate_def by auto next assume assm: "si > 0 \ si' > 0 \ unat (a' - a) \ si \ unat (a - a') \ si'" then have "unat (x - a') \ si'" if "unat (x - a) < si" for x using that apply (auto simp add: unat_sub_if' split: if_split_asm) apply (meson Nat.le_diff_conv2 add_increasing le_less_trans less_imp_le_nat unsigned_greater_eq unsigned_less) - by (smt (z3) Nat.le_diff_conv2 add_leD2 le_less_trans linorder_not_less nat_le_linear unat_lt2p) + by (smt (verit) Nat.le_diff_conv2 add_leD2 le_less_trans linorder_not_less nat_le_linear unat_lt2p) then have "region_addresses a si \ region_addresses a' si' = {}" by (simp add: region_addresses_iff disjoint_iff leD) with assm show "separate a si a' si'" by (simp add: separate_def) qed lemma separate_as_linarith: assumes "\region_overflow a si" and "\region_overflow a' si'" shows "separate a si a' si' \ 0 < si \ 0 < si' \ (a + of_nat si \ a' \ a' + of_nat si' \ a)" (is "?lhs \ ?rhs") proof assume ?lhs then show ?rhs by (meson separate_iff le_less le_plus not_le_imp_less word_of_nat_le) next have *: "separate a si a' si'" if "si > 0" and "si' > 0" and "a + of_nat si \ a'" and "\region_overflow a si" and "\region_overflow a' si'" for a si a' si' proof - from that have "unat a + si < 2^LENGTH('a)" and "unat a' + si' < 2^LENGTH('a)" by (meson not_le region_overflow_def)+ have "x < a + of_nat si" if "x \ region_addresses a si" for x - by (smt (z3) Abs_fnat_hom_add \unat a + si < 2 ^ LENGTH('a)\ add.commute dual_order.trans le_add1 less_diff_conv2 not_less region_addresses_iff that unat_of_nat_len unat_sub_if' word_less_iff_unsigned word_unat.Rep_inverse) + by (smt (verit) Abs_fnat_hom_add \unat a + si < 2 ^ LENGTH('a)\ add.commute dual_order.trans le_add1 less_diff_conv2 not_less region_addresses_iff that unat_of_nat_len unat_sub_if' word_less_iff_unsigned word_unat.Rep_inverse) moreover have "x \ a'" if "x \ region_addresses a' si'" for x using address_in_enclosed_region_as_linarith enclosed_def \unat a' + si' < 2 ^ LENGTH('a)\ that by blast ultimately show ?thesis using separate_def that by fastforce qed assume ?rhs then show ?lhs by (meson "*" assms separate_symm) qed text \Compute separation in case the addresses and sizes are immediate values.\ lemmas separate_as_linarith_numeral [simp] = separate_as_linarith [of "numeral a::'a word" "numeral si" "numeral a'::'a word" "numeral si'"] for a si a' si' lemmas separate_as_linarith_numeral_1 [simp] = separate_as_linarith [of "numeral a::'a word" "numeral si" "numeral a'::'a word" "Suc 0"] for a si a' lemmas separate_as_linarith_numeral1_ [simp] = separate_as_linarith [of "numeral a::'a word" "Suc 0" "numeral a'::'a word" "numeral si'"] for a a' si' lemmas separate_as_linarith_numeral11 [simp] = separate_as_linarith [of "numeral a::'a word" "Suc 0" "numeral a'::'a word" "Suc 0"] for a a' lemmas region_overflow_numeral[simp] = region_overflow_def [of "numeral a::'a word" "numeral si"] for a si lemmas region_overflow_numeral1[simp] = region_overflow_def [of "numeral a::'a word" "Suc 0"] for a lemma separate_plus_none: assumes "si' \ unat offset" and "0 < si" and "0 < si'" and "unat offset + si \ 2^LENGTH('a)" shows "separate (offset + a) si a si'" using assms apply (auto simp add: separate_iff) - by (smt (z3) Nat.diff_diff_right add.commute add_leD1 diff_0 diff_is_0_eq diff_zero not_gr_zero unat_sub_if' unsigned_0) + by (smt (verit) Nat.diff_diff_right add.commute add_leD1 diff_0 diff_is_0_eq diff_zero not_gr_zero unat_sub_if' unsigned_0) lemmas unat_minus = unat_sub_if'[of 0,simplified] lemma separate_minus_minus': assumes "si \ 0" and "si' \ 0" and "unat offset \ si" and "unat offset' \ si'" and "unat offset - si \ unat offset'" shows "separate (a - offset) si (a - offset') si'" using assms apply (auto simp add: separate_iff) apply (metis Nat.le_diff_conv2 add.commute add_leD2 unat_sub_if') - by (smt (z3) add.commute add_diff_cancel_right' diff_add_cancel diff_le_self diff_less less_le_trans nat_le_linear not_le unat_sub_if') + by (smt (verit) add.commute add_diff_cancel_right' diff_add_cancel diff_le_self diff_less less_le_trans nat_le_linear not_le unat_sub_if') lemma separate_minus_minus: assumes "si \ 0" and "si' \ 0" and "unat offset \ si" and "unat offset' \ si'" and "unat offset - si \ unat offset' \ unat offset' - si' \ unat offset" shows "separate (a - offset) si (a - offset') si'" by (meson assms separate_minus_minus' separate_symm) lemma separate_minus_none: assumes "si \ 0" and "si' \ 0" and "unat offset \ si" and "si' \ 2^LENGTH('a) - unat offset" shows "separate (a - offset) si a si'" proof - have "0 < si" and "0 < si'" using assms(1,2) by blast+ moreover have "\ offset \ 0" using assms(1) assms(3) by fastforce ultimately show ?thesis - by (smt (z3) add_diff_cancel_left' assms(3,4) diff_diff_eq2 diff_zero le_add_diff_inverse less_or_eq_imp_le separate_iff unat_sub_if' unsigned_0 unsigned_less word_less_eq_iff_unsigned) + by (simp add: assms(3) assms(4) local.unat_minus separate_iff unsigned_eq_0_iff) qed text \The following theorems are used during symbolic execution to determine whether two regions are separate.\ lemmas separate_simps = separate_plus_none separate_minus_none separate_minus_minus end end \ No newline at end of file diff --git a/thys/X86_Semantics/ROOT b/thys/X86_Semantics/ROOT --- a/thys/X86_Semantics/ROOT +++ b/thys/X86_Semantics/ROOT @@ -1,17 +1,13 @@ chapter AFP session "X86_Semantics" = HOL + - options [timeout = 1800] sessions - "HOL-Eisbach" - Word_Lib - + "HOL-Eisbach" + Word_Lib theories Examples Example_WC - document_files "root.bib" "root.tex" -