Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  Gabow_SCC.thy

  Sprache: Isabelle
 

section Enumerating the SCCs of a Graph \label{sec:scc}
theory Gabow_SCC
imports Gabow_Skeleton
begin

text 
 As a first variant, we implement an algorithm that computes a list of SCCs
 of a graph, in topological order. This is the standard variant described by
 Gabow~cite"Gabow00".
 


section Specification
context fr_graph
begin
  text We specify a distinct list that covers all reachable nodes and
 contains SCCs in topological order


  definition "compute_SCC_spec SPEC (λl.
    distinct l (set l) = E*``V0 (Uset l. is_scc E U)
     (i j. i<j j<length l l!j × l!i E* = {}) )"
end

section Extended Invariant

locale cscc_invar_ext = fr_graph G
  for G :: "('v,'more) graph_rec_scheme" +
  fixes l :: "'v set list" and D :: "'v set"
  assumes l_is_D: "(set l) = D"  The output contains all done CNodes
  assumes l_scc: "set l Collect (is_scc E)"  The output contains only SCCs
  assumes l_no_fwd: "i j. [i<j; j<length l] ==> l!j × l!i E* = {}"
     The output contains no forward edges
begin
  lemma l_no_empty: "{}set l" using l_scc by (auto simp: in_set_conv_decomp)
end

locale cscc_outer_invar_loc = outer_invar_loc G it D + cscc_invar_ext G l D
  for G :: "('v,'more) graph_rec_scheme" and it l D
begin
  lemma locale_this: "cscc_outer_invar_loc G it l D" by unfold_locales
  lemma abs_outer_this: "outer_invar_loc G it D" by unfold_locales
end

locale cscc_invar_loc = invar_loc G v0 D0 p D pE + cscc_invar_ext G l D
  for G :: "('v,'more) graph_rec_scheme" and v0 D0 and l :: "'v set list"
  and p D pE
begin
  lemma locale_this: "cscc_invar_loc G v0 D0 l p D pE" by unfold_locales
  lemma invar_this: "invar_loc G v0 D0 p D pE" by unfold_locales
end

context fr_graph
begin
  definition "cscc_outer_invar λit (l,D). cscc_outer_invar_loc G it l D"
  definition "cscc_invar λv0 D0 (l,p,D,pE). cscc_invar_loc G v0 D0 l p D pE"
end

section Definition of the SCC-Algorithm

context fr_graph
begin
  definition compute_SCC :: "'v set list nres" where
    "compute_SCC do {
      let so = ([],{});
      (l,D) FOREACHi cscc_outer_invar V0 (λv0 (l,D0). do {
        if v0D0 then do {
          let s = (l,initial v0 D0);

          (l,p,D,pE)
          WHILEIT (cscc_invar v0 D0)
            (λ(l,p,D,pE). p []) (λ(l,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
                  RETURN (l,collapse v (p,D,pE))
                } else if vD then do {
                   Edge to new node. Append to path
                  RETURN (l,push v (p,D,pE))
                } else RETURN (l,p,D,pE)
              }
            | None ==> do {
                 No more outgoing edges from current node on path
                ASSERT (pE last p × UNIV = {});
                let V = last p;
                let (p,D,pE) = pop (p,D,pE);
                let l = V#l;
                RETURN (l,p,D,pE)
              }
          }) s;
          ASSERT (p=[] pE={});
          RETURN (l,D)
        } else
          RETURN (l,D0)
      }) so;
      RETURN l
    }"
end

section Preservation of Invariant Extension
context cscc_invar_ext
begin
  lemma l_disjoint:
    assumes A: "i<j" "j<length l"
    shows "l!i l!j = {}"
  proof (rule disjointI)
    fix u
    assume "ul!i" "ul!j"
    with l_no_fwd A show False by auto
  qed

  corollary l_distinct: "distinct l"
    using l_disjoint l_no_empty
    by (metis distinct_conv_nth inf_idem linorder_cases nth_mem)
end

context fr_graph
begin
  definition "cscc_invar_part λ(l,p,D,pE). cscc_invar_ext G l D"

  lemma cscc_invarI[intro?]:
    assumes "invar v0 D0 PDPE"
    assumes "invar v0 D0 PDPE ==> cscc_invar_part (l,PDPE)"
    shows "cscc_invar v0 D0 (l,PDPE)"
    using assms
    unfolding initial_def cscc_invar_def invar_def
    apply (simp split: prod.split_asm)
    apply intro_locales
    apply (simp add: invar_loc_def)
    apply (simp add: cscc_invar_part_def cscc_invar_ext_def)
    done

  thm cscc_invarI[of v_0 D_0 s l]

  lemma cscc_outer_invarI[intro?]:
    assumes "outer_invar it D"
    assumes "outer_invar it D ==> cscc_invar_ext G l D"
    shows "cscc_outer_invar it (l,D)"
    using assms
    unfolding initial_def cscc_outer_invar_def outer_invar_def
    apply (simp split: prod.split_asm)
    apply intro_locales
    apply (simp add: outer_invar_loc_def)
    apply (simp add: cscc_invar_ext_def)
    done

  lemma cscc_invar_initial[simp, intro!]:
    assumes A: "v0it" "v0D0"
    assumes INV: "cscc_outer_invar it (l,D0)"
    shows "cscc_invar_part (l,initial v0 D0)"
  proof -
    from INV interpret cscc_outer_invar_loc G it l D0
      unfolding cscc_outer_invar_def by simp

    show ?thesis
      unfolding cscc_invar_part_def initial_def
      apply simp
      by unfold_locales
  qed

  lemma cscc_invar_pop:
    assumes INV: "cscc_invar v0 D0 (l,p,D,pE)"
    assumes "invar v0 D0 (pop (p,D,pE))"
    assumes NE[simp]: "p[]"
    assumes NO': "pE (last p × UNIV) = {}"
    shows "cscc_invar_part (last p # l, pop (p,D,pE))"
  proof -
    from INV interpret cscc_invar_loc G v0 D0 l p D pE
      unfolding cscc_invar_def by simp

    have AUX_l_scc: "is_scc E (last p)"
      unfolding is_scc_pointwise
    proof safe
      {
        assume "last p = {}" thus False
          using p_no_empty by (cases p rule: rev_cases) auto
      }

      fix u v
      assume "ulast p" "vlast p"
      with p_sc[of "last p"have "(u,v) (lvE last p × last p)*" by auto
      with lvE_ss_E show "(u,v)(E last p × last p)*"
        by (metis Int_mono equalityE rtrancl_mono_mp)

      fix u'
      assume "u'last p" "(u,u')E*" "(u',v)E*"

      from u'last p ulast p (u,u')E*
        and rtrancl_reachable_induct[OF order_refl lastp_un_D_closed[OF NE NO']]
      have "u'D" by auto
      with (u',v)E* and rtrancl_reachable_induct[OF order_refl D_closed]
      have "vD" by auto
      with vlast p p_not_D show False by (cases p rule: rev_cases) auto
    qed

    {
      fix i j
      assume A: "i<j" "j<Suc (length l)"
      have "l ! (j - Suc 0) × (last p # l) ! i E* = {}"
      proof (rule disjointI, safe)
        fix u v
        assume "(u, v) E*" "u l ! (j - Suc 0)" "v (last p # l) ! i"
        from u l ! (j - Suc 0)have "u(set l)"
          by (metis Ex_list_of_length Suc_pred UnionI length_greater_0_conv
            less_nat_zero_code not_less_eq nth_mem)
        with l_is_D have "uD" by simp
        with rtrancl_reachable_induct[OF order_refl D_closed] (u,v)E*
        have "vD" by auto

        show False proof cases
          assume "i=0" hence "vlast p" using v (last p # l) ! i by simp
          with p_not_D vD show False by (cases p rule: rev_cases) auto
        next
          assume "i0" with v (last p # l) ! i have "vl!(i - 1)" by auto
          with l_no_fwd[of "i - 1" "j - 1"]
            and u l ! (j - Suc 0) (u, v) E* i0 A
          show False by fastforce
        qed
      qed
    } note AUX_l_no_fwd = this

    show ?thesis
      unfolding cscc_invar_part_def pop_def apply simp
      apply unfold_locales
      apply clarsimp_all
      using l_is_D apply auto []

      using l_scc AUX_l_scc apply auto []

      apply (rule AUX_l_no_fwd, assumption+) []
      done
  qed

  thm cscc_invar_pop[of v_0 D_0 l p D pE]

  lemma cscc_invar_unchanged:
    assumes INV: "cscc_invar v0 D0 (l,p,D,pE)"
    shows "cscc_invar_part (l,p',D,pE')"
    using INV unfolding cscc_invar_def cscc_invar_part_def cscc_invar_loc_def
    by simp

  corollary cscc_invar_collapse:
    assumes INV: "cscc_invar v0 D0 (l,p,D,pE)"
    shows "cscc_invar_part (l,collapse v (p',D,pE'))"
    unfolding collapse_def
    by (simp add: cscc_invar_unchanged[OF INV])

  corollary cscc_invar_push:
    assumes INV: "cscc_invar v0 D0 (l,p,D,pE)"
    shows "cscc_invar_part (l,push v (p',D,pE'))"
    unfolding push_def
    by (simp add: cscc_invar_unchanged[OF INV])


  lemma cscc_outer_invar_initial: "cscc_invar_ext G [] {}"
    by unfold_locales auto


  lemma cscc_invar_outer_newnode:
    assumes A: "v0D0" "v0it"
    assumes OINV: "cscc_outer_invar it (l,D0)"
    assumes INV: "cscc_invar v0 D0 (l',[],D',pE)"
    shows "cscc_invar_ext G l' D'"
  proof -
    from OINV interpret cscc_outer_invar_loc G it l D0
      unfolding cscc_outer_invar_def by simp
    from INV interpret inv: cscc_invar_loc G v0 D0 l' "[]" D' pE
      unfolding cscc_invar_def by simp

    show ?thesis
      by unfold_locales

  qed

  lemma cscc_invar_outer_Dnode:
    assumes "cscc_outer_invar it (l, D)"
    shows "cscc_invar_ext G l D"
    using assms
    by (simp add: cscc_outer_invar_def cscc_outer_invar_loc_def)

  lemmas cscc_invar_preserve = invar_preserve
    cscc_invar_initial
    cscc_invar_pop cscc_invar_collapse cscc_invar_push cscc_invar_unchanged
    cscc_outer_invar_initial cscc_invar_outer_newnode cscc_invar_outer_Dnode

  text On termination, the invariant implies the specification
  lemma cscc_finI:
    assumes INV: "cscc_outer_invar {} (l,D)"
    shows fin_l_is_scc: "[Uset l] ==> is_scc E U"
    and fin_l_distinct: "distinct l"
    and fin_l_is_reachable: "(set l) = E* `` V0"
    and fin_l_no_fwd: "[i<j; j<length l] ==> l!j ×l!i E* = {}"
  proof -
    from INV interpret cscc_outer_invar_loc G "{}" l D
      unfolding cscc_outer_invar_def by simp

    show "[Uset l] ==> is_scc E U" using l_scc by auto

    show "distinct l" by (rule l_distinct)

    show "(set l) = E* `` V0"
      using fin_outer_D_is_reachable[OF outer_invar_this] l_is_D
      by auto

    show "[i<j; j<length l] ==> l!j ×l!i E* = {}"
      by (rule l_no_fwd)

  qed

end

section Main Correctness Proof

context fr_graph
begin
  lemma invar_from_cscc_invarI: "cscc_invar v0 D0 (L,PDPE) ==> invar v0 D0 PDPE"
    unfolding cscc_invar_def invar_def
    apply (simp split: prod.splits)
    unfolding cscc_invar_loc_def by simp

  lemma outer_invar_from_cscc_invarI:
    "cscc_outer_invar it (L,D) ==>outer_invar it D"
    unfolding cscc_outer_invar_def outer_invar_def
    apply (simp split: prod.splits)
    unfolding cscc_outer_invar_loc_def by simp

  text With the extended invariant and the auxiliary lemmas, the actual
 correctness proof is straightforward:

  theorem compute_SCC_correct: "compute_SCC compute_SCC_spec"
  proof -
    note [[goals_limit = 2]]
    note [simp del] = Union_iff

    show ?thesis
      unfolding compute_SCC_def compute_SCC_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
      )

      apply (vc_solve
        rec: cscc_invarI cscc_outer_invarI
        solve: cscc_invar_preserve cscc_finI
        intro: invar_from_cscc_invarI outer_invar_from_cscc_invarI
        dest!: sym[of "pop A" for A]
        simp: pE_fin'[OF invar_from_cscc_invarI] finite_V0
      )
      apply auto
      done
  qed


  text Simple proof, for presentation
  context
    notes [refine]=refine_vcg
    notes [[goals_limit = 1]]
  begin
    theorem "compute_SCC compute_SCC_spec"
      unfolding compute_SCC_def compute_SCC_spec_def select_edge_def select_def
      by (refine_rcg
        WHILEIT_rule[where R="inv_image (abs_wf_rel v0) snd" for v0])
      (vc_solve
        rec: cscc_invarI cscc_outer_invarI solve: cscc_invar_preserve cscc_finI
        intro: invar_from_cscc_invarI outer_invar_from_cscc_invarI
        dest!: sym[of "pop A" for A]
        simp: pE_fin'[OF invar_from_cscc_invarI] finite_V0, auto)
  end

end


section Refinement to Gabow's Data Structure

context GS begin
  definition "seg_set_impl l u do {
    (_,res) WHILET
      (λ(l,_). l<u)
      (λ(l,res). do {
        ASSERT (l<length S);
        let x = S!l;
        ASSERT (xres);
        RETURN (Suc l,insert x res)
      })
      (l,{});

    RETURN res
  }"

  lemma seg_set_impl_aux:
    fixes l u
    shows "[l<u; ulength S; distinct S] ==> seg_set_impl l u
     SPEC (λr. r = {S!j | j. lj j<u})"
    unfolding seg_set_impl_def
    apply (refine_rcg
      WHILET_rule[where
        I="λ(l',res). res = {S!j | j. lj j<l'} ll' l'u"
        and R="measure (λ(l',_). u-l')"
      ]
      refine_vcg)

    apply (auto simp: less_Suc_eq nth_eq_iff_index_eq)
    done

  lemma (in GS_invar) seg_set_impl_correct:
    assumes "i<length B"
    shows "seg_set_impl (seg_start i) (seg_end i) SPEC (λr. r=p_α!i)"
    apply (refine_rcg order_trans[OF seg_set_impl_aux] refine_vcg)

    using assms
    apply (simp_all add: seg_start_less_end seg_end_bound S_distinct) [3]

    apply (auto simp: p_α_def assms seg_def) []
    done

  definition "last_seg_impl
     do {
      ASSERT (length B - 1 < length B);
      seg_set_impl (seg_start (length B - 1)) (seg_end (length B - 1))
    }"

  lemma (in GS_invar) last_seg_impl_correct:
    assumes "p_α []"
    shows "last_seg_impl SPEC (λr. r=last p_α)"
    unfolding last_seg_impl_def
    apply (refine_rcg order_trans[OF seg_set_impl_correct] refine_vcg)
    using assms apply (auto simp add: p_α_def last_conv_nth)
    done

end

context fr_graph
begin

  definition "last_seg_impl s GS.last_seg_impl s"
  lemmas last_seg_impl_def_opt =
    last_seg_impl_def[abs_def, THEN opt_GSdef,
      unfolded GS.last_seg_impl_def GS.seg_set_impl_def
    GS.seg_start_def GS.seg_end_def GS_sel_simps]
    (* TODO: Some potential for optimization here: the assertion
      guarantees that length B - 1 + 1 = length B !*)


  lemma last_seg_impl_refine:
    assumes A: "(s,(p,D,pE))GS_rel"
    assumes NE: "p[]"
    shows "last_seg_impl s Id (RETURN (last p))"
  proof -
    from A have
      [simp]: "p=GS.p_α s D=GS.D_α s pE=GS.pE_α s"
        and INV: "GS_invar s"
      by (auto simp add: GS_rel_def br_def GS_α_split)

    show ?thesis
      unfolding last_seg_impl_def[abs_def]
      apply (rule order_trans[OF GS_invar.last_seg_impl_correct])
      using INV NE
      apply (simp_all)
      done
  qed

  definition compute_SCC_impl :: "'v set list nres" where
    "compute_SCC_impl do {
      stat_start_nres;
      let so = ([],Map.empty);
      (l,D) FOREACHi (λit (l,s). cscc_outer_invar it (l,oGS_α s))
        V0 (λv0 (l,I0). do {
          if ¬is_done_oimpl v0 I0 then do {
            let ls = (l,initial_impl v0 I0);

            (l,(S,B,I,P))WHILEIT (λ(l,s). cscc_invar v0 (oGS_α I0) (l,GS.α s))
              (λ(l,s). ¬path_is_empty_impl s) (λ(l,s).
            do {
               Select edge from end of path
              (vo,s) select_edge_impl s;

              case vo of
                Some v ==> do {
                  if is_on_stack_impl v s then do {
                    scollapse_impl v s;
                    RETURN (l,s)
                  } else if ¬is_done_impl v s then do {
                     Edge to new node. Append to path
                    RETURN (l,push_impl v s)
                  } else do {
                     Edge to done node. Skip
                    RETURN (l,s)
                  }
                }
              | None ==> do {
                   No more outgoing edges from current node on path
                  scc last_seg_impl s;
                  spop_impl s;
                  let l = scc#l;
                  RETURN (l,s)
                }
            }) (ls);
            RETURN (l,I)
          } else RETURN (l,I0)
      }) so;
      stat_stop_nres;
      RETURN l
    }"

  lemma compute_SCC_impl_refine: "compute_SCC_impl Id compute_SCC"
  proof -
    note [refine2] = bind_Let_refine2[OF last_seg_impl_refine]

    have [refine2]: "s' p D pE l' l v' v. [
      (s',(p,D,pE))GS_rel;
      (l',l)Id;
      (v',v)Id;
      v(set p)
    ] ==> do { s'collapse_impl v' s'; RETURN (l',s') }
       (Id ×r GS_rel) (RETURN (l,collapse v (p,D,pE)))"
      apply (refine_rcg order_trans[OF collapse_refine] refine_vcg)
      apply assumption+
      apply (auto simp add: pw_le_iff refine_pw_simps)
      done

    note [[goals_limit = 1]]
    show ?thesis
      unfolding compute_SCC_impl_def compute_SCC_def
      apply (refine_rcg
        bind_refine'
        select_edge_refine push_refine
        pop_refine
        (*collapse_refine*)
        initial_refine
        oinitial_refine
        (*last_seg_impl_refine*)
        prod_relI IdI
        inj_on_id
      )

      apply refine_dref_type
      apply (vc_solve (nopre) solve: asm_rl I_to_outer
        simp: GS_rel_def br_def GS.α_def oGS_rel_def oGS_α_def
        is_on_stack_refine path_is_empty_refine is_done_refine is_done_orefine
      )

      done
  qed

end

end

Messung V0.5 in Prozent
C=92 H=99 G=95

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen



NIST Cobol Testsuite



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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

      Eigene Quellcodes
      Fremde Quellcodes
     Quellcodebibliothek
      Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge