Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Isabelle/Archive-of-Formal-Proofs/thys/Gabow_SCC/   (Sammlung formaler Beweise Version 2026-5©)  Datei vom 29.4.2026 mit Größe 76 kB image not shown  

Quelle  Gabow_GBG.thy

  Sprache: Isabelle
 

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)* `` g_V0 G)"
  shows "igb_fr_graph G"
proof -
  interpret igb_graph G by fact
  show ?thesis using assms(2by 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*``V0 Vl E*``V0 ― Only reachable nodes are covered
       set prVr set plVl ― The paths are inside the specified sets
       Vl×Vl (E Vl×Vl)*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 ¬(vD. pl. pl[] path E v pl v
    (i<num_acc. qset pl. iacc 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
    (i<num_acc. qset pl. iacc 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 v0D0 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 i<num_acc. qlast p. iacc q then
                      RETURN (Some ((set (butlast p)),last p),p,D,pE)
                    else
                      RETURN (None,p,D,pE)
                  } else if vD 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: "v0it" "v0D0"
    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"vD0"
        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 v0D0
      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: "i<num_acc. qlast p. iacc 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*" "wlast p"
    proof cases
      assume "length p = 1"
      hence "v0last p"
        using root_v0 
        by (cases p) auto
      thus thesis by (auto intro: that)
    next
      assume "length p1"
      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: "up!(length p - 2)" and VIP: "vp!(length p - 1)" and "(u,v)lvE"
        using length p > 1 by auto
      from root_v0 have V0IP: "v0p!0" by (cases p) auto
      
      from VIP have "vlast 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)))*"
        (is "_ *")  
        by (simp add: path_seg_butlast)
      also have " ?Er" using lvE_ss_E by auto
      finally (rtrancl_mono_mp[rotated]) have "(v0,u)?Er*" .
      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
         (i<num_acc. qset pl. iacc 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" "ulast p" "vlast p"
          by auto
        from cnode_connectedI wlast p ulast p
        have "(w,u)(lvE last p × last p)*"
          by auto
        also note (u,v)lvE last p × last p
        also (rtrancl_into_trancl1) from cnode_connectedI vlast p wlast p
        have "(v,w)(lvE last p × last p)*"
          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 "i<n. qlast p. iacc q" by auto
        with Suc.IH obtain pl where IH: 
          "pl[]" 
          "path (lvE last p × last p) w pl w" 
          "i<n. qset pl. iacc q" 
          by blast
  
        from Suc.prems obtain v where "vlast p" and "nacc v" by auto
        from cnode_connectedI wlast p vlast p
        have "(w,v)(lvE last p × last p)*" 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 wlast p vlast p
        have "(v,w)(lvE last p × last p)*" 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(1have "pl1@pl2@pl []" by simp
        moreover have "i'<n. qset (pl1@pl2@pl). i'acc q" using IH(3by auto
        moreover have "vset (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 nacc v have "qset (pl1@pl2@pl). nacc 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" 
      "i<num_acc. qset pl. iacc 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)*" by auto
    with lvE_ss_E have VL_CLOSED: "last p × last p (E last p × last p)*"
      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*``V0" 
      and BLP_REACH: "(set (butlast p)) E*``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 "ulast p"
    assumes BACK"v(set p)"
    assumes ACC: "i<num_acc. qlast p'. iacc 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 BACKhave "i<length p" and "vp!i" 
      by (simp_all add: i_def)

    have "ulast p'" 
      using ulast p i<length p
      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 "vlast p'" 
      using vp!i i<length p
      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 "ulast p"
    assumes BACK"v(set p)"
    assumes NACC: "j<num_acc" "qlast p'. jacc 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 BACKhave "i<length p" and "vp!i" 
      by (simp_all add: i_def)

    have "ulast p'" 
      using ulast p i<length p
      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 "vlast p'" 
      using vp!i i<length p
      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 "i<num_acc. qset pl. iacc q"
      proof cases
        assume "set pl last p' = {}" 
          ― Case: The loop is outside the last Cnode
        with path_restrict[OF P] ulast p' vlast 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 "wlast 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'_defapply 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: "ulast p"
    assumes VNE: "v(set p)" "vD"
    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 "i<num_acc. qset pl. iacc q" 
      proof cases
        assume "vset 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: "vset 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 "wset 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: "ulast p"
    assumes VID: "vD"
    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 "i<num_acc. qset pl. iacc 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: "wD" 
          using VID by (auto dest!: path_is_rtrancl)
        from split(1) WID D_closed_vE_rtrancl have "uD"
          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: "v0D0" "v0it" 
    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: "vD'" "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: "v0D0" "v0it" 
    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)" "vD"
    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*``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)*
           is_lasso_prpl (pr,pl));
        (pr,pl) SPEC (λ(pr,pl).
           set pr Vr
           set pl Vl
           Vl × Vl (E Vl×Vl)*
           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 (prpl\<omega>)
    )"
    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;
      osFOREACHci fgl_outer_invar V0 (go_is_no_brk) (λv0 s0. do {
        if v0goD 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..<num_acc} then
                    RETURN (Some ((set (butlast p)),last p),a,p,D,pE)
                  else
                    RETURN (None,a,p,D,pE)
                } else if vD 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×rId" by simp

  lemma gselect_edge_refine: "[(s',s)gstate_rel] ==> gselect_edge s'
    (Idoption_rel ×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..<num_acc}) = (i<num_acc. qlast p. iacc 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<length A);
      let res = A!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)))) ii'" 
    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,{})RRs"
  assumes [autoref_rules]: "(un_impl,())RRsRRsRRs"
  shows "(?c,Un_set_drop_impl)nat_rel RRsas_rel RRsnres_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 {} (RRs)"
  assumes "GEN_OP un_impl () (RRsRRsRRs)"
  shows "(λi A. RETURN (Un_set_drop_tr es_impl un_impl i A),Un_set_drop_impl)
    nat_rel RRsas_rel RRsnres_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..<num_acc}
  "

definition gGS_α :: "'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..<num_acc}"
    using assms
    apply (cases s')
    apply (simp add: gGS_rel_def br_def gGS_α_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..<num_acc}"
      by (rule gGS_relE)
    {
      fix S B I P S' B' I' P'
      assume "push_impl v (S, B, I, P) = (S', B', I', P')"
      hence "length B' = Suc (length B)" 
        by (auto simp add: push_impl_def GS.push_impl_def Let_def)  
    } note AUX1=this

    from push_refine[OF OSR A PRE] A L acc_bound R show ?thesis
      unfolding gpush_impl_def gpush_def
        gGS_rel_def gGS_invar_def gGS_α_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;
    spop_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..<num_acc}"
      by (rule gGS_relE)

    from PRE OSR have [simp]: "a[]" 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 ×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..<num_acc}"
      by (rule gGS_relE)

    {
      fix S B I P S' B' I' P' vo
      assume "nofail (select_edge_impl ((S, B, I, P)::'a GS))"
        "inres (select_edge_impl ((S, B, I, P)::'a GS)) (vo, (S', B', I', P'))"
      hence "length B' = length B"
        apply (simp add: select_edge_impl_def GS.sel_rem_last_def refine_pw_simps
          split: if_split_asm prod.splits)
        apply auto
        done
    } note AUX1=this

    show ?thesis
      using select_edge_refine[OF OSR PRE]
      unfolding gselect_edge_impl_def gselect_edge_def
      apply (simp add: refine_pw_simps pw_le_iff prod_rel_sv)

      unfolding gGS_rel_def br_def gGS_α_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;
      🍋ASSERT (vset (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..<num_acc}"
      by (rule gGS_relE)

    from B have [simp]: "v'=v" by simp

    from OSR have [simp]: "GS.p_α (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 PREapply 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);
      usUn_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: "v0goD 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<u
    | _ ==> False"

  definition (in -) "on_stack_ge I l v
    case I v of
      Some (STACK j) ==> lj
    | _ ==> 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 "j<last B"
        by (auto simp: on_stack_less_def split: option.splits node_state.splits)

      from I_consistent[of v j] have [simp]: "j<length S" "v=S!j" by auto
      
      from B0 have "B!0=0" by simp
      from j<last B have "j<B!(length B - 1)" by (simp add: last_conv_nth)
      from find_seg_bounds[OF j<length S] find_seg_correct[OF j<length S]
      have "vseg (find_seg j)" "find_seg j < length B" by auto
      moreover with j<B!(length B - 1) 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) \<le> j`)*)

      proof -
        have f1: "x1 x. ¬ (x1::nat) < x1 - x"
          using less_imp_diff_less by blast
        have "j last B"
          by (metis j < last B less_le)
        hence f2: "x1. ¬ last B < x1 ¬ x1 j"
          using f1 by (metis diff_diff_cancel le_trans)
        have "x1. seg_end x1 j ¬ x1 < 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 "i<length B - 1" and "vseg 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<B!(i+1)" and "i+1 length B - 1" using i<length B - 1
        by (auto simp: seg_end_def last_conv_nth split: if_split_asm)
      with sorted_nth_mono[OF B_sorted i+1 length B - 1have "j<last B"
        by (auto simp: last_conv_nth)
      moreover from j < seg_end i have "j<length S"
        by (metis GS.seg_end_def add_diff_inverse_nat i + 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 "jlast B"
        by (auto simp: on_stack_ge_def split: option.splits node_state.splits)

      from I_consistent[of v j] have [simp]: "j<length S" "v=S!j" by auto
      hence "vseg (length B - 1)" using jlast B
        by (auto simp: seg_def last_conv_nth seg_start_def seg_end_def)
      thus "vlast p_α" by (auto simp: p_α_def last_map)
    }

    {
      fix v
      assume "v?R"
      hence "vseg (length B - 1)"
        by (auto simp: p_α_def last_map)
      then obtain j where "v=S!j" "jlast B" "j<length S"
        by (auto simp: seg_def last_conv_nth seg_start_def seg_end_def)
      with I_consistent have "I v = Some (STACK j)" by simp
      with jlast 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×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 (i<num_acc. 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..<num_acc})"
  proof -
    from A PRE have "last a {0..<num_acc}"
      unfolding gGS_rel_def gGS_invar_def br_def gGS_α_def by auto
    hence C: "(i<num_acc. ilast a) (last a = {0..<num_acc})"
      by auto

    from A obtain gs where [simp]: "s=(a,gs)"
      by (auto simp: gGS_rel_def gGS_α_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;
      osFOREACHci (λ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 {
                  sgcollapse_impl v s;
                  blast_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
                sgpop_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 ×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 (EVr×UNIV) V0 (λv. vVl);
      ASSERT (res None);
      RETURN (the res)
    }"

  lemma reconstruct_reach_correct:
    assumes CEC: "ce_correct Vr Vl"
    shows "reconstruct_reach Vr Vl
       SPEC (λ(pr,va). v0V0. path E v0 pr va vaVl)"
  proof -
    have FIN_aux: "finite ((E Vr × UNIV)* `` 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 "v0V0" "set pr Vr" "vaVl" 
      "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)* `` 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 vaVl 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*``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..<num_acc};
    let E = E UNIV×Vl;
    
    (vd,p,_) WHILEIT (rec_loop_invar Vl va)
      (λ(_,_,cS). cS cS_full)
      (λ(v,p,cS). do {
        ASSERT (v'. (v,v')E* ¬ (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*``V0"
    and CONN: "Vl×Vl (E Vl×Vl)*"
    and NONTRIV: "Vl×Vl E {}"
    and NES[simp]: "Vl{}"
    and ALL: "(acc`Vl) = {0..<num_acc}"
    unfolding ce_correct_def is_lasso_prpl_def
    apply clarsimp_all
    apply auto []
    apply force
    done

  define term_rel
    where "term_rel = (inv_image (finite_psupset {0..<num_acc}) (λ(_::'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)* `` {v})"
      apply -
      apply (rule finite_subset[where B="E*``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..<num_acc}"

    from NC INV obtain i where "i<num_acc" "icS" 
      unfolding rec_loop_invar_def by auto blast

    with ALL obtain v' where v': "v'Vl" "¬ acc v' cS"
      by (metis NES atLeastLessThan_iff cSUP_least in_mono zero_le)
     
    with CONN INV have "(v,v')(E Vl × Vl)*"
      unfolding rec_loop_invar_def by auto
    hence "(v,v')?E*" using rtrancl_mono_mp[OF E_SS] by blast
    with v' have "v'. (v,v')(?E)* ¬ 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 "vset 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 "vset 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)+"
  proof clarify
    fix a b
    assume "aVl" "bVl"
    from NONTRIV obtain u v where E: "(u,v)(E Vl×Vl)" by auto
    from CONN aVlhave "(a,u)(EVl×Vl)*" by auto
    also note E
    also (rtrancl_into_trancl1) from CONN bVlhave "(v,b)(EVl×Vl)*"
      by auto
    finally show "(a,b)(?E)+" 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)+"
      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)*"
      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..<num_acc})" "va 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..<num_acc})" 
      and 1"p[]" "path ?E v p' va"
      and PR"v0V0" "path E v0 pr va"

    from INV have "i<num_acc. qinsert 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: "i<num_acc. qset 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

Messung V0.5 in Prozent
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.93 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.