Theory DFS_Invars_SCC

section ‹Invariants for SCCs›
theory DFS_Invars_SCC
imports 
  DFS_Invars_Basic
begin

definition scc_root' :: "('v × 'v) set  ('v,'es) state_scheme   'v  'v set  bool"
    ― ‹@{term v} is a root of its scc 
        iff all the discovered parts of the scc can be reached by tree edges from @{term v}
  where
  "scc_root' E s v scc  is_scc E scc 
                        v  scc
                        v  dom (discovered s) 
                        scc  dom (discovered s)  (tree_edges s)* `` {v}"

context param_DFS_defs begin
  abbreviation "scc_root  scc_root' E"
  lemmas scc_root_def = scc_root'_def

  lemma scc_rootI:
    assumes "is_scc E scc"
    and "v  dom (discovered s)"
    and "v  scc"
    and "scc  dom (discovered s)  (tree_edges s)* `` {v}"
    shows "scc_root s v scc"
    using assms by (simp add: scc_root_def)

  definition "scc_roots s = {v. scc. scc_root s v scc}"
end

context DFS_invar begin
  lemma scc_root_is_discovered:
    "scc_root s v scc  v  dom (discovered s)"
    by (simp add: scc_root_def)

  lemma scc_root_scc_tree_rtrancl:
    assumes "scc_root s v scc"
    and "x  scc" "x  dom (discovered s)"
    shows "(v,x)  (tree_edges s)*"
    using assms
    by (auto simp add: scc_root_def)

  lemma scc_root_scc_reach:
    assumes "scc_root s r scc"
    and "v  scc"
    shows "(r,v)  E*"
  proof -
    from assms have "is_scc E scc" "r  scc" by (simp_all add: scc_root_def)
    with is_scc_connected assms show ?thesis by metis
  qed

  lemma scc_reach_scc_root:
    assumes "scc_root s r scc"
    and "v  scc"
    shows "(v,r)  E*"
  proof -
    from assms have "is_scc E scc" "r  scc" by (simp_all add: scc_root_def)
    with is_scc_connected assms show ?thesis by metis
  qed

  lemma scc_root_scc_tree_trancl:
    assumes "scc_root s v scc"
    and "x  scc" "x  dom (discovered s)" "x  v"
    shows "(v,x)  (tree_edges s)+"
    using assms scc_root_scc_tree_rtrancl
    by (auto simp add: rtrancl_eq_or_trancl)

  lemma scc_root_unique_scc:
    "scc_root s v scc  scc_root s v scc'  scc = scc'"
    unfolding scc_root_def
    by (metis is_scc_unique)

  lemma scc_root_unique_root:
    assumes scc1: "scc_root s v scc"
    and scc2: "scc_root s v' scc"
    shows "v = v'"
  proof (rule ccontr)
    assume "v  v'"
    from scc1 have "v  scc" "v  dom (discovered s)" 
      by (simp_all add: scc_root_def)
    with scc_root_scc_tree_trancl[OF scc2] v  v' have "(v',v)  (tree_edges s)+" 
      by simp
    also from scc2 have "v'  scc" "v'  dom (discovered s)" 
      by (simp_all add: scc_root_def)
    with scc_root_scc_tree_trancl[OF scc1] vv' have "(v,v')  (tree_edges s)+" 
      by simp
    finally show False using no_loop_in_tree by contradiction
  qed

  lemma scc_root_unique_is_scc:
    assumes "scc_root s v scc"
    shows "scc_root s v (scc_of E v)"
  proof -
    from assms have "v  scc" "is_scc E scc" by (simp_all add: scc_root_def)
    moreover have "v  scc_of E v" "is_scc E (scc_of E v)" by simp_all
    ultimately have "scc = scc_of E v" using is_scc_unique by metis
    thus ?thesis using assms by simp
  qed

  lemma scc_root_finished_impl_scc_finished:
    assumes "v  dom (finished s)"
    and "scc_root s v scc"
    shows "scc  dom (finished s)"
  proof
    fix x
    assume "x  scc"

    let ?E = "Restr E scc"

    from assms have "is_scc E scc" "v  scc" by (simp_all add: scc_root_def)
    hence "(v,x)  (Restr E scc)*" using x  scc
      by (simp add: is_scc_connected')
    with rtrancl_is_path obtain p where "path ?E v p x" by metis
    thus "x  dom (finished s)" 
    proof (induction p arbitrary: x rule: rev_induct)
      case Nil hence "v = x" by simp
      with assms show ?case by simp
    next
      case (snoc y ys) hence "path ?E v ys y" "(y,x)  ?E" 
        by (simp_all add: path_append_conv)
      with snoc.IH have "y  dom (finished s)" by simp
      moreover from (y,x)  ?E have "(y,x)  E" "x  scc" by auto
      ultimately have "x  dom (discovered s)"
        using finished_imp_succ_discovered
        by blast
      with x  scc show ?case
        using assms scc_root_scc_tree_trancl tree_path_impl_parenthesis
        by blast
    qed
  qed

context begin interpretation timing_syntax .
  lemma scc_root_disc_le:
    assumes "scc_root s v scc"
    and "x  scc" "x  dom (discovered s)"
    shows "δ s v  δ s x"
  proof (cases "x = v")
    case False with assms scc_root_scc_tree_trancl tree_path_disc have 
      "δ s v < δ s x" 
      by blast
    thus ?thesis by simp
  qed simp

  lemma scc_root_fin_ge:
    assumes "scc_root s v scc"
    and "v  dom (finished s)"
    and "x  scc"
    shows "φ s v  φ s x"
  proof (cases "x = v")
    case False
    from assms scc_root_finished_impl_scc_finished have 
      "x  dom (finished s)" by auto
    hence "x  dom (discovered s)" using finished_discovered by auto
    with assms False have "(v,x)  (tree_edges s)+" 
      using scc_root_scc_tree_trancl by simp
    with tree_path_impl_parenthesis assms False show ?thesis by force
  qed simp

  lemma scc_root_is_Min_disc:
    assumes "scc_root s v scc"
    shows "Min (δ s ` (scc  dom (discovered s))) = δ s v" (is "Min ?S = _")
  proof (rule Min_eqI)
    from discovered_finite show "finite ?S" by auto
    from scc_root_disc_le[OF assms] show "y. y  ?S  δ s v  y" by force
    
    from assms have "v  scc" "v  dom (discovered s)"
      by (simp_all add: scc_root_def)
    thus "δ s v  ?S" by auto
  qed

  lemma Min_disc_is_scc_root:
    assumes "v  scc" "v  dom (discovered s)"
    and "is_scc E scc"
    and min: "δ s v = Min (δ s ` (scc  dom (discovered s)))"
    shows "scc_root s v scc"
  proof -
    {
      fix y
      assume A: "y  scc" "y  dom (discovered s)" "y  v"
      with min have "δ s v  δ s y" by auto
      with assms disc_unequal A have "δ s v < δ s y" by fastforce
    } note scc_disc = this

    {
      fix x
      assume A: "x  scc  dom (discovered s)"

      have "x  (tree_edges s)* `` {v}"
      proof (cases "v = x")
        case False with A scc_disc have δ: "δ s v < δ s x" by simp

        have "(v,x)  (tree_edges s)+"
        proof (cases "v  dom (finished s)")
          case False with stack_set_def assms have 
            v_stack: "v  set (stack s)" by auto
          show ?thesis
          proof (cases "x  dom (finished s)")
            case True 
            with parenthesis_impl_tree_path_not_finished[of v x] assms δ False
            show ?thesis by auto
          next
            case False with A stack_set_def have "x  set (stack s)" by auto
            with v_stack δ show ?thesis
              using on_stack_is_tree_path
              by simp
          qed
        next
          case True note v_fin = this

          let ?E = "Restr E scc"

          {
            fix y
            assume "(v, y)  ?E" and "v  y"
            hence *: "y  succ v" "y  scc" by auto
            with finished_imp_succ_discovered v_fin have 
              "y  dom (discovered s)" by simp
            with scc_disc v  y * have "δ s v < δ s y" by simp
            with * finished_succ_impl_path_in_tree v_fin have "(v,y)  (tree_edges s)+" by simp
          } note trancl_base = this

          from A have "x  scc" by simp
          with assms have "(v,x)  ?E*"
            by (simp add: is_scc_connected')
          with vx have "(v,x)  ?E+" by (metis rtrancl_eq_or_trancl)
          thus ?thesis using vx
          proof (induction)
            case (base y) with trancl_base show ?case .
          next
            case (step y z)
            show ?case
            proof (cases "v = y")
              case True with step trancl_base show ?thesis by simp
            next
              case False with step have "(v,y)  (tree_edges s)+" by simp
              with tree_path_impl_parenthesis[OF _ v_fin] have 
                y_fin: "y  dom (finished s)" 
                and y_t: "δ s v < δ s y" "φ s y < φ s v" 
                by auto
              with finished_discovered have y_disc: "y  dom (discovered s)" 
                by auto

              from step have *: "z  succ y" "z  scc" by auto
              with finished_imp_succ_discovered y_fin have 
                z_disc: "z  dom (discovered s)" by simp
              with * vz have δz: "δ s v < δ s z" by (simp add: scc_disc)
              

              from * edges_covered finished_no_pending[OF y  dom (finished s)] 
                   y_disc have "(y,z)  edges s" by auto
              thus ?thesis
              proof safe
                assume "(y,z)  tree_edges s" with (v,y)  (tree_edges s)+ show ?thesis ..
              next
                assume CE: "(y,z)  cross_edges s" 
                with cross_edges_finished_decr y_fin y_t have "φ s z < φ s v" 
                  by force
                moreover note δz
                moreover from CE cross_edges_target_finished have 
                  "z  dom (finished s)" by simp
                ultimately show ?thesis 
                  using parenthesis_impl_tree_path[OF v_fin] by metis
              next
                assume BE: "(y,z)  back_edges s" 
                with back_edge_disc_lt_fin y_fin y_t have 
                  "δ s z < φ s v" by force
                moreover note δz
                moreover note z_disc
                ultimately have "z  dom (finished s)" "φ s z < φ s v" 
                  using parenthesis_contained[OF v_fin] by simp_all
                with δz show ?thesis 
                  using parenthesis_impl_tree_path[OF v_fin] by metis
              qed
            qed
          qed
        qed
        thus ?thesis by auto
      qed simp
    }
    hence "scc  dom (discovered s)  (tree_edges s)* `` {v}" by blast

    with assms show ?thesis by (auto intro: scc_rootI)
  qed

  lemma scc_root_iff_Min_disc:
    assumes "is_scc E scc" "r  scc" "r  dom (discovered s)"
    shows "scc_root s r scc  Min (δ s ` (scc  dom (discovered s))) = δ s r" (is "?L  ?R")
  proof
    assume "?L" with scc_root_is_Min_disc show "?R" .
  next
    assume "?R" with Min_disc_is_scc_root assms show "?L" by simp
  qed   

  lemma scc_root_exists:
    assumes "is_scc E scc"
    and scc: "scc  dom (discovered s)  {}"
    shows "r. scc_root s r scc"
  proof -
    let ?S = "scc  dom (discovered s)"

    from discovered_finite have "finite (δ s`?S)" by auto
    moreover from scc have "δ s ` ?S  {}" by auto
    moreover have "(x::nat) f A. x  f ` A  (y. x = f y  y  A)" by blast 
      ― ‹autogenerated by sledgehammer›
    ultimately have "x  ?S. δ s x = Min (δ s ` ?S)" by (metis Min_in)
    with Min_disc_is_scc_root is_scc E scc show ?thesis by auto
  qed

  lemma scc_root_of_node_exists:
    assumes "v  dom (discovered s)"
    shows "r. scc_root s r (scc_of E v)"
  proof -
    have "is_scc E (scc_of E v)" by simp
    moreover have "v  scc_of E v" by simp
    with assms have "scc_of E v  dom (discovered s)  {}" by blast
    ultimately show ?thesis using scc_root_exists by metis
  qed

  lemma scc_root_transfer':
    assumes "discovered s = discovered s'" "tree_edges s = tree_edges s'"
    shows "scc_root s r scc  scc_root s' r scc"
    unfolding scc_root_def
    by (simp add: assms)

  lemma scc_root_transfer:
    assumes inv: "DFS_invar G param s'"
    assumes r_d: "r  dom (discovered s)"
    assumes d: "dom (discovered s)  dom (discovered s')"
               "xdom (discovered s). δ s x = δ s' x"
               "xdom (discovered s') - dom (discovered s). δ s' x  counter s"
    and t: "tree_edges s  tree_edges s'"
    shows "scc_root s r scc  scc_root s' r scc"
  proof -
    interpret s': DFS_invar where s=s' by fact

    let ?sd = "scc  dom (discovered s)"
    let ?sd' = "scc  dom (discovered s')"
    let ?sdd = "scc  (dom (discovered s') - dom (discovered s))"

    {
      assume r_s: "r  scc" "is_scc E scc"
      with r_d have ne: "δ s'`?sd  {}" by blast
      from discovered_finite have fin: "finite (δ s' ` ?sd)" by simp
    
      from timing_less_counter d have "x. xδ s' ` ?sd  x < counter s" by auto
      hence Min: "Min (δ s' ` ?sd) < counter s"
        using Min_less_iff[OF fin] ne by blast

      from d have "Min (δ s ` ?sd) = Min (δ s' ` ?sd)" by (auto simp: image_def)
      also from d have "?sd' = ?sd  ?sdd" by auto
      hence *: "δ s' ` ?sd' = δ s' ` ?sd  δ s' ` ?sdd" by auto
      hence "Min (δ s' ` ?sd) = Min (δ s' ` ?sd')"
      proof (cases "?sdd = {}")
        case False
        from d have "x. x  δ s' ` ?sdd  x  counter s" by auto
        moreover from False have ne': "δ s' ` ?sdd  {}" by blast
        moreover from s'.discovered_finite have fin': "finite (δ s' ` ?sdd)" by blast
        ultimately have "Min (δ s' ` ?sdd)  counter s"
          using Min_ge_iff by metis
        with Min Min_Un[OF fin ne fin' ne'] * show ?thesis by simp
      qed simp
      finally have "Min (δ s ` ?sd) = Min (δ s' ` ?sd')" .
    } note aux = this

    show ?thesis
    proof
      assume r: "scc_root s r scc"
      from r_d d have "δ s' r = δ s r" by simp
      also from r scc_root_is_Min_disc have "δ s r = Min (δ s ` ?sd)" by simp
      also from r aux have "Min (δ s ` ?sd) = Min (δ s' ` ?sd')" by (simp add: scc_root_def)
      finally show "scc_root s' r scc"
        using r_d d r[unfolded scc_root_def]
        by (blast intro!: s'.Min_disc_is_scc_root)
    next
      assume r': "scc_root s' r scc"
      from r_d d have "δ s r = δ s' r" by simp
      also from r' s'.scc_root_is_Min_disc have "δ s' r = Min (δ s' ` ?sd')" by simp
      also from r' aux have "Min (δ s' ` ?sd') = Min (δ s ` ?sd)" by (simp add: scc_root_def)
      finally show "scc_root s r scc"
        using r_d d r'[unfolded scc_root_def]
        by (blast intro!: Min_disc_is_scc_root)
    qed
  qed

end end

end