# Theory DFS_Framework.DFS_Invars_Basic

```section ‹Basic Invariant Library›
theory DFS_Invars_Basic
imports "../Param_DFS"
begin

text ‹We provide more basic invariants of the DFS algorithm›

subsection ‹Basic Timing Invariants›

(* Timing *)
abbreviation "the_discovered s v ≡ the (discovered s v)"
abbreviation "the_finished s v ≡ the (finished s v)"

locale timing_syntax
begin
(* Timing related syntax shortcuts *)
notation the_discovered ("δ")
notation the_finished ("φ")
end

context param_DFS begin context begin interpretation timing_syntax .

definition "timing_common_inv s ≡
― ‹‹δ s v < φ s v››
(∀v ∈ dom (finished s). δ s v < φ s v)

― ‹‹v ≠ w ⟶ δ s v ≠ δ s w ∧ φ s v ≠ φ s w››
― ‹Can't use ‹card dom = card ran› as the maps may be infinite ...›
∧ (∀v ∈ dom (discovered s). ∀w ∈ dom (discovered s). v ≠ w ⟶ δ s v ≠ δ s w)
∧ (∀v ∈ dom (finished s). ∀w ∈ dom (finished s). v ≠ w ⟶ φ s v ≠ φ s w)

― ‹‹δ s v < counter ∧ φ s v < counter››
∧ (∀v ∈ dom (discovered s). δ s v < counter s)
∧ (∀v ∈ dom (finished s). φ s v < counter s)

∧ (∀v ∈ dom (finished s). ∀w ∈ succ v. δ s w < φ s v)"

lemma timing_common_inv:
"is_invar timing_common_inv"
proof (induction rule: is_invarI)
case (finish s s') then interpret DFS_invar where s=s by simp

from finish have NE: "stack s ≠ []" by (simp add: cond_alt)

have *: "hd (stack s) ∉ dom (finished s)" "hd (stack s) ∈ dom (discovered s)"
using stack_not_finished stack_discovered hd_in_set[OF NE]
by blast+

from discovered_closed have
"(E - pending s) `` {hd (stack s)} ⊆ dom (discovered s)"
using hd_in_set[OF NE]
hence succ_hd: "pending s `` {hd (stack s)} = {}
⟹ succ (hd (stack s)) ⊆ dom (discovered s)"
by blast

from finish show ?case
apply (intro conjI)
using * apply simp
using * apply simp
apply (metis less_irrefl)
apply (metis less_irrefl)
apply (metis less_SucI)
apply (metis less_SucI)
apply (blast dest!: succ_hd)
using * apply simp
done
next
case (discover s) then interpret DFS_invar where s=s by simp
from discover show ?case
apply (intro conjI)
using finished_discovered apply fastforce
apply (metis less_irrefl)
apply (metis less_irrefl)
apply (metis less_SucI)
apply (metis less_SucI)
using finished_imp_succ_discovered apply fastforce
done
next
case (new_root s s' v0) then interpret DFS_invar where s=s by simp
from new_root show ?case
apply (intro conjI)
using finished_discovered apply fastforce
apply (metis less_irrefl)
apply (metis less_irrefl)
apply (metis less_SucI)
apply (metis less_SucI)
using finished_imp_succ_discovered apply fastforce
done
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemmas s_timing_common_inv =
timing_common_inv[THEN make_invar_thm]

lemma timing_less_counter:
"v ∈ dom (discovered s) ⟹ δ s v < counter s"
"v ∈ dom (finished s) ⟹ φ s v < counter s"
using s_timing_common_inv

lemma disc_lt_fin:
"v ∈ dom (finished s) ⟹ δ s v < φ s v"
using s_timing_common_inv

lemma disc_unequal:
assumes "v ∈ dom (discovered s)" "w ∈ dom (discovered s)"
and "v ≠ w"
shows "δ s v ≠ δ s w"
using s_timing_common_inv assms

lemma fin_unequal:
assumes "v ∈ dom (finished s)" "w ∈ dom (finished s)"
and "v ≠ w"
shows "φ s v ≠ φ s w"
using s_timing_common_inv assms

lemma finished_succ_fin:
assumes "v ∈ dom (finished s)"
and "w ∈ succ v"
shows "δ s w < φ s v"
using assms s_timing_common_inv
end end

context param_DFS begin context begin interpretation timing_syntax .

lemma i_prev_stack_discover_all:
"is_invar (λs. ∀ n < length (stack s). ∀ v ∈ set (drop (Suc n) (stack s)).
δ s (stack s ! n) > δ s v)"
proof (induct rule: is_invarI)
case (finish s) thus ?case
by (cases "stack s") auto
next
case (discover s s' u v)
hence EQ[simp]: "discovered s' = (discovered s)(v ↦ counter s)"
"stack s' = v#stack s"
by simp_all

from discover interpret DFS_invar where s=s by simp
from discover stack_discovered have v_ni: "v ∉ set (stack s)" by auto

from stack_discovered timing_less_counter have
"⋀w. w ∈ set (stack s) ⟹ δ s w < counter s"
by blast
with v_ni have "⋀w. w ∈ set (stack s) ⟹ δ s' w < δ s' v" by auto
hence "⋀w. w ∈ set (drop (Suc 0) (stack s')) ⟹ δ s' w < δ s' (stack s' ! 0)"
by auto

moreover
from v_ni have
"⋀n. ⟦n < (length (stack s')); n > 0⟧
⟹ δ s' (stack s' ! n) = δ s (stack s' ! n)"
by auto
with discover(1) v_ni
have  "⋀n. ⟦n < (length (stack s')) - 1; n > 0⟧
⟹ ∀ w ∈ set (drop (Suc n) (stack s')). δ s' (stack s' ! n) > δ s' w"
by (auto dest: in_set_dropD)
ultimately show ?case
by (metis drop_Suc_Cons length_drop length_pos_if_in_set length_tl
list.sel(3) neq0_conv nth_Cons_0 EQ(2) zero_less_diff)
qed simp_all
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemmas prev_stack_discover_all
= i_prev_stack_discover_all[THEN make_invar_thm]

lemma prev_stack_discover:
"⟦n < length (stack s); v ∈ set (drop (Suc n) (stack s)) ⟧
⟹ δ s (stack s ! n) > δ s v"
by (metis prev_stack_discover_all)

lemma Suc_stack_discover:
assumes n: "n < (length (stack s)) - 1"
shows "δ s (stack s ! n) > δ s (stack s ! Suc n)"
proof -
from prev_stack_discover assms have
"⋀ v. v ∈ set (drop (Suc n) (stack s)) ⟹ δ s (stack s ! n) > δ s v"
by fastforce
moreover from n have "stack s ! Suc n ∈ set (drop (Suc n) (stack s))"
using in_set_conv_nth by fastforce
ultimately show ?thesis .
qed

lemma tl_lt_stack_hd_discover:
assumes notempty: "stack s ≠ []"
and "x ∈ set (tl (stack s))"
shows "δ s x < δ s (hd (stack s))"
proof -
from notempty obtain y ys where "stack s = y#ys" by (metis list.exhaust)
with assms show ?thesis
using prev_stack_discover
by (cases ys) force+
qed

lemma stack_nth_order:
assumes l: "i < length (stack s)" "j < length (stack s)"
shows "δ s (stack s ! i) < δ s (stack s ! j) ⟷ i > j" (is "δ s ?i < δ s ?j ⟷ _")
proof
assume δ: "δ s ?i < δ s ?j"

from l stack_set_def have
disc: "?i ∈ dom (discovered s)" "?j ∈ dom (discovered s)"
by auto
with disc_unequal[OF disc] δ have "i ≠ j" by auto

moreover
{
assume "i < j"

with l have "stack s ! j ∈ set (drop (Suc i) (stack s))"
using in_set_drop_conv_nth[of "stack s ! j" "Suc i" "stack s"]
by fastforce
with prev_stack_discover l have "δ s (stack s ! j) < δ s (stack s ! i)"
by simp
with δ have "False" by simp
}
ultimately show "i > j" by force
next
assume "i > j"
with l have "stack s ! i ∈ set (drop (Suc j) (stack s))"
using in_set_drop_conv_nth[of "stack s ! i" "Suc j" "stack s"]
by fastforce
with prev_stack_discover l show "δ s ?i < δ s ?j" by simp
qed
end end

subsection ‹Paranthesis Theorem›
(* Parenthesis Thm *)
context param_DFS begin context begin interpretation timing_syntax .

definition "parenthesis s ≡
∀v ∈ dom (discovered s). ∀w ∈ dom (discovered s).
δ s v < δ s w ∧ v ∈ dom (finished s) ⟶ (
φ s v < δ s w ― ‹disjoint›
∨ (φ s v > δ s w ∧ w ∈ dom (finished s) ∧ φ s w < φ s v))"

lemma i_parenthesis: "is_invar parenthesis"
proof (induct rule: is_invarI)
case (finish s s')
hence EQ[simp]: "discovered s' = discovered s"
"counter s' = Suc (counter s)"
"finished s' = (finished s)(hd (stack s) ↦ counter s)"
by simp_all

from finish interpret DFS_invar where s=s by simp
from finish have NE[simp]: "stack s ≠ []" by (simp add: cond_alt)

{
fix x y
assume  dom: "x ∈ dom (discovered s')" "y ∈ dom (discovered s')"
and δ: "δ s' x < δ s' y"
and f: "x ∈ dom (finished s')"
hence neq: "x ≠ y" by force

note assms = dom δ f EQ

let ?DISJ = "φ s' x < δ s' y"
let ?IN = "δ s' y < φ s' x ∧ y ∈ dom (finished s') ∧ φ s' y < φ s' x"

have "?DISJ ∨ ?IN"
proof (cases "x = hd (stack s)")
case True note x_is_hd = this
hence φx: "φ s' x = counter s" by simp
from x_is_hd neq have y_not_hd: "y ≠ hd (stack s)" by simp

have "δ s y < φ s' x ∧ y ∈ dom (finished s) ∧ φ s y < φ s' x"
proof (cases "y ∈ set (stack s)")
― ‹y on stack is not possible: According to @{thm [display] δ} it is discovered after @{text "x (= hd (stack s))"}›
case True with y_not_hd have "y ∈ set (tl (stack s))"
by (cases "stack s") simp_all
with tl_lt_stack_hd_discover[OF NE] δ x_is_hd have "δ s y < δ s x"
by simp
with δ have False by simp
thus ?thesis ..
next
case False ― ‹y must be a successor of @{text "x (= (hd (stack s)))"}›
from dom have "y ∈ dom (discovered s)" by simp
with False discovered_not_stack_imp_finished  have *:
"y ∈ dom (finished s)"
by simp
moreover with timing_less_counter φx have "φ s y < φ s' x" by simp
moreover with * disc_lt_fin φx have "δ s y < φ s' x"
by (metis less_trans)
ultimately show ?thesis by simp
qed
with y_not_hd show ?thesis by simp
next
case False note [simp] = this
show ?thesis
proof (cases "y = hd (stack s)")
case False with finish assms show ?thesis
next
case True with stack_not_finished have "y ∉ dom (finished s)"
using hd_in_set[OF NE]
by auto
with finish assms have "φ s x < δ s y"
unfolding parenthesis_def
by auto
hence ?DISJ by simp
thus ?thesis ..
qed
qed
}
thus ?case by (simp add: parenthesis_def)
next
case (discover s s' u v)
hence EQ[simp]: "discovered s' = (discovered s)(v ↦ counter s)"
"finished s' = finished s"
"counter s' = Suc (counter s)"
by simp_all

from discover interpret DFS_invar where s=s by simp
from discover finished_discovered have
V': "v ∉ dom (discovered s)" "v ∉ dom (finished s)"
by auto

{
fix x y
assume  dom: "x ∈ dom (discovered s')" "y ∈ dom (discovered s')"
and δ: "δ s' x < δ s' y"
and f: "x ∈ dom (finished s')"

let ?DISJ = "φ s' x < δ s' y"
let ?IN = "δ s' y < φ s' x ∧ y ∈ dom (finished s') ∧ φ s' y < φ s' x"

from dom V' f have x: "x ∈ dom (discovered s)""x ≠ v" by auto

have "?DISJ ∨ ?IN"
proof (cases "y = v")
case True hence "δ s' y = counter s" by simp
moreover from timing_less_counter x f have "φ s' x < counter s" by auto
ultimately have "?DISJ" by simp
thus ?thesis ..
next
case False with dom have "y ∈ dom (discovered s)" by simp
with discover False δ f x show ?thesis by (simp add: parenthesis_def)
qed
}
thus ?case by (simp add: parenthesis_def)
next
case (new_root s s' v0)
then interpret DFS_invar where s=s by simp

from finished_discovered new_root have "v0 ∉ dom (finished s')" by auto
with new_root timing_less_counter show ?case by (simp add: parenthesis_def)
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemma parenthesis:
assumes "v ∈ dom (finished s)" "w ∈ dom (discovered s)"
and "δ s v < δ s w"
shows "φ s v < δ s w ― ‹disjoint›
∨ (φ s v > δ s w ∧ w ∈ dom (finished s) ∧ φ s w < φ s v)"
using assms
using i_parenthesis[THEN make_invar_thm]
using finished_discovered
unfolding parenthesis_def
by blast

lemma parenthesis_contained:
assumes "v ∈ dom (finished s)" "w ∈ dom (discovered s)"
and "δ s v < δ s w" "φ s v > δ s w"
shows "w ∈ dom (finished s) ∧ φ s w < φ s v"
using parenthesis assms
by force

lemma parenthesis_disjoint:
assumes "v ∈ dom (finished s)" "w ∈ dom (discovered s)"
and "δ s v < δ s w" "φ s w > φ s v"
shows "φ s v < δ s w"
using parenthesis assms
by force

lemma finished_succ_contained:
assumes "v ∈ dom (finished s)"
and "w ∈ succ v"
and "δ s v < δ s w"
shows "w ∈ dom (finished s) ∧ φ s w < φ s v"
using finished_succ_fin finished_imp_succ_discovered parenthesis_contained
using assms
by metis

end end

subsection ‹Edge Types›
context param_DFS
begin
abbreviation "edges s ≡ tree_edges s ∪ cross_edges s ∪ back_edges s"

(* Demo for simple invariant proof *)
lemma "is_invar (λs. finite (edges s))"
by (induction rule: establish_invarI) auto

text ‹Sometimes it's useful to just chose between tree-edges and non-tree.›
lemma edgesE_CB:
assumes "x ∈ edges s"
and "x ∈ tree_edges s ⟹ P"
and "x ∈ cross_edges s ∪ back_edges s ⟹ P"
shows "P"
using assms by auto

definition "edges_basic s ≡
Field (back_edges s) ⊆ dom (discovered s) ∧ back_edges s ⊆ E - pending s
∧ Field (cross_edges s) ⊆ dom (discovered s) ∧ cross_edges s ⊆ E - pending s
∧ Field (tree_edges s) ⊆ dom (discovered s) ∧ tree_edges s ⊆ E - pending s
∧ back_edges s ∩ cross_edges s = {}
∧ back_edges s ∩ tree_edges s = {}
∧ cross_edges s ∩ tree_edges s = {}
"

lemma i_edges_basic:
"is_invar edges_basic"
unfolding edges_basic_def[abs_def]
proof (induct rule: is_invarI_full)
case (back_edge s)
then interpret DFS_invar where s=s by simp
from back_edge show ?case by (auto dest: pendingD)
next
case (cross_edge s)
then interpret DFS_invar where s=s by simp
from cross_edge show ?case by (auto dest: pendingD)
next
case (discover s)
then interpret DFS_invar where s=s by simp
from discover show ?case
(* Speed optimized proof, using only auto takes too long *)
apply (simp add: Field_def Range_def Domain_def)
apply (drule pendingD) apply simp
by (blast)
next
case (new_root s)
thus ?case by (simp add: Field_def) blast
qed auto

lemmas (in DFS_invar) edges_basic = i_edges_basic[THEN make_invar_thm]

lemma i_edges_covered:
"is_invar (λs. (E ∩ dom (discovered s) × UNIV) - pending s = edges s)"
proof (induction rule: is_invarI_full)
case (new_root s s' v0)
interpret DFS_invar G param s by fact

from new_root empty_stack_imp_empty_pending
have [simp]: "pending s = {}" by simp

from ‹v0 ∉ dom (discovered s)›
have [simp]: "E ∩ insert v0 (dom (discovered s)) × UNIV - {v0} × succ v0
= E ∩ dom (discovered s) × UNIV" by auto

from new_root show ?case by simp
next
case (cross_edge s s' u v)
interpret DFS_invar G param s by fact

from cross_edge stack_discovered have "u ∈ dom (discovered s)"
by (cases "stack s") auto

with cross_edge(2-) pending_ssE have
"E ∩ dom (discovered s) × UNIV - (pending s - {(hd (stack s), v)})
= insert (hd (stack s), v) (E ∩ dom (discovered s) × UNIV - pending s)"
by auto

thus ?case using cross_edge by simp
next
case (back_edge s s' u v)
interpret DFS_invar G param s by fact

from back_edge stack_discovered have "u ∈ dom (discovered s)"
by (cases "stack s") auto

with back_edge(2-) pending_ssE have
"E ∩ dom (discovered s) × UNIV - (pending s - {(hd (stack s), v)})
= insert (hd (stack s), v) (E ∩ dom (discovered s) × UNIV - pending s)"
by auto

thus ?case using back_edge by simp
next
case (discover s s' u v)
interpret DFS_invar G param s by fact

from discover stack_discovered have "u ∈ dom (discovered s)"
by (cases "stack s") auto

with discover(2-) pending_ssE have
"E ∩ insert v (dom (discovered s)) × UNIV
- (pending s - {(hd (stack s), v)} ∪ {v} × succ v)
= insert (hd (stack s), v) (E ∩ dom (discovered s) × UNIV - pending s)"
by auto

thus ?case using discover by simp
qed simp_all
end

context DFS_invar begin

lemmas edges_covered =
i_edges_covered[THEN make_invar_thm]

lemma edges_ss_reachable_edges:
"edges s ⊆ E ∩ reachable × UNIV"
using edges_covered discovered_reachable

lemma nc_edges_covered:
assumes "¬cond s" "¬is_break param s"
shows "E ∩ reachable × UNIV = edges s"
proof -
from assms have [simp]: "stack s = []"
unfolding cond_def by (auto simp: pred_defs)
hence [simp]: "pending s = {}" by (rule empty_stack_imp_empty_pending)

from edges_covered nc_discovered_eq_reachable[OF assms]
show ?thesis by simp
qed

lemma
tree_edges_ssE: "tree_edges s ⊆ E" and
tree_edges_not_pending: "tree_edges s ⊆ - pending s" and
tree_edge_is_succ: "(v,w) ∈ tree_edges s ⟹ w ∈ succ v" and
tree_edges_discovered: "Field (tree_edges s) ⊆ dom (discovered s)" and

cross_edges_ssE: "cross_edges s ⊆ E" and
cross_edges_not_pending: "cross_edges s ⊆ - pending s" and
cross_edge_is_succ: "(v,w) ∈ cross_edges s ⟹ w ∈ succ v" and
cross_edges_discovered: "Field (cross_edges s) ⊆ dom (discovered s)" and

back_edges_ssE: "back_edges s ⊆ E" and
back_edges_not_pending: "back_edges s ⊆ - pending s" and
back_edge_is_succ: "(v,w) ∈ back_edges s ⟹ w ∈ succ v" and
back_edges_discovered: "Field (back_edges s) ⊆ dom (discovered s)"
using edges_basic
unfolding edges_basic_def
by auto

lemma edges_disjoint:
"back_edges s ∩ cross_edges s = {}"
"back_edges s ∩ tree_edges s = {}"
"cross_edges s ∩ tree_edges s = {}"
using edges_basic
unfolding edges_basic_def
by auto

lemma tree_edge_imp_discovered:
"(v,w) ∈ tree_edges s ⟹ v ∈ dom (discovered s)"
"(v,w) ∈ tree_edges s ⟹ w ∈ dom (discovered s)"
using tree_edges_discovered

lemma back_edge_imp_discovered:
"(v,w) ∈ back_edges s ⟹ v ∈ dom (discovered s)"
"(v,w) ∈ back_edges s ⟹ w ∈ dom (discovered s)"
using back_edges_discovered

lemma cross_edge_imp_discovered:
"(v,w) ∈ cross_edges s ⟹ v ∈ dom (discovered s)"
"(v,w) ∈ cross_edges s ⟹ w ∈ dom (discovered s)"
using cross_edges_discovered

lemma edge_imp_discovered:
"(v,w) ∈ edges s ⟹ v ∈ dom (discovered s)"
"(v,w) ∈ edges s ⟹ w ∈ dom (discovered s)"
using tree_edge_imp_discovered cross_edge_imp_discovered back_edge_imp_discovered
by blast+

lemma tree_edges_finite[simp, intro!]: "finite (tree_edges s)"
using finite_subset[OF tree_edges_discovered discovered_finite] by simp

lemma cross_edges_finite[simp, intro!]: "finite (cross_edges s)"
using finite_subset[OF cross_edges_discovered discovered_finite] by simp

lemma back_edges_finite[simp, intro!]: "finite (back_edges s)"
using finite_subset[OF back_edges_discovered discovered_finite] by simp

lemma edges_finite: "finite (edges s)"
by auto

end

subsubsection ‹Properties of the DFS Tree›
(* Tree *)

context DFS_invar begin context begin interpretation timing_syntax .
lemma tree_edge_disc_lt_fin:
"(v,w) ∈ tree_edges s ⟹ v ∈ dom (finished s) ⟹ δ s w < φ s v"
by (metis finished_succ_fin tree_edge_is_succ)

lemma back_edge_disc_lt_fin:
"(v,w) ∈ back_edges s ⟹ v ∈ dom (finished s) ⟹ δ s w < φ s v"
by (metis finished_succ_fin back_edge_is_succ)

lemma cross_edge_disc_lt_fin:
"(v,w) ∈ cross_edges s ⟹ v ∈ dom (finished s) ⟹ δ s w < φ s v"
by (metis finished_succ_fin cross_edge_is_succ)
end end

(* Stack & Tree *)
context param_DFS begin

lemma i_stack_is_tree_path:
"is_invar (λs. stack s ≠ [] ⟶ (∃v0 ∈ V0.
path (tree_edges s) v0 (rev (tl (stack s))) (hd (stack s))))"
proof (induct rule: is_invarI)
case (discover s s' u v)
hence EQ[simp]: "stack s' = v # stack s"
"tree_edges s' = insert (hd (stack s), v) (tree_edges s)"
by simp_all
from discover have NE[simp]: "stack s ≠ []" by simp

from discover obtain v0 where
"v0 ∈ V0"
"path (tree_edges s) v0 (rev (tl (stack s))) (hd (stack s))"
by blast
with path_mono[OF _ this(2)] EQ have
"path (tree_edges s') v0 (rev (tl (stack s))) (hd (stack s))"
by blast
with ‹v0 ∈ V0› show ?case
by (cases "stack s") (auto simp: path_simps)

next
case (finish s s')
hence EQ[simp]: "stack s' = tl (stack s)"
"tree_edges s' = tree_edges s"
by simp_all

from finish obtain v0 where
"v0 ∈ V0"
"path (tree_edges s) v0 (rev (tl (stack s))) (hd (stack s))"
by blast
hence P: "path (tree_edges s') v0 (rev (stack s')) (hd (stack s))" by simp

show ?case
proof
assume A: "stack s' ≠ []"
with P have "(hd (stack s'), hd (stack s)) ∈ tree_edges s'"
by (auto simp: neq_Nil_conv path_simps)
moreover from P A have
"path (tree_edges s') v0 (rev (tl (stack s')) @ [hd (stack s')]) (hd (stack s))"
by (simp)
moreover note ‹v0 ∈ V0›
ultimately show "∃v0∈V0. path (tree_edges s') v0 (rev (tl (stack s'))) (hd (stack s'))"
qed
qed simp_all
end

context DFS_invar begin

lemmas stack_is_tree_path =
i_stack_is_tree_path[THEN make_invar_thm, rule_format]

lemma stack_is_path:
"stack s ≠ [] ⟹ ∃v0∈V0. path E v0 (rev (tl (stack s))) (hd (stack s))"
using stack_is_tree_path path_mono[OF tree_edges_ssE]
by blast

lemma hd_succ_stack_is_path:
assumes ne: "stack s ≠ []"
and succ: "v ∈ succ (hd (stack s))"
shows "∃v0∈V0. path E v0 (rev (stack s)) v"
proof -
from stack_is_path[OF ne] succ obtain v0 where
"v0 ∈ V0"
"path E v0 (rev (tl (stack s)) @ [hd (stack s)]) v"
thus ?thesis using ne
by (cases "stack s") auto
qed

lemma tl_stack_hd_tree_path:
assumes "stack s ≠ []"
and "v ∈ set (tl (stack s))"
shows "(v, hd (stack s)) ∈ (tree_edges s)⇧+"
proof -
from stack_is_tree_path assms obtain v0 where
"path (tree_edges s) v0 (rev (tl (stack s))) (hd (stack s))"
by auto
from assms path_member_reach_end[OF this] show ?thesis by simp
qed
end

context param_DFS begin
definition "tree_discovered_inv s ≡
(tree_edges s = {} ⟶ dom (discovered s) ⊆ V0 ∧ (stack s = [] ∨ (∃v0∈V0. stack s = [v0])))
∧ (tree_edges s ≠ {} ⟶ (tree_edges s)⇧+ `` V0 ∪ V0 = dom (discovered s) ∪ V0)"

lemma i_tree_discovered_inv:
"is_invar tree_discovered_inv"
proof (induct rule: is_invarI)
case (discover s s' u v)
hence EQ[simp]: "stack s' = v # stack s"
"tree_edges s' = insert (hd (stack s), v) (tree_edges s)"
"discovered s' = (discovered s)(v ↦ counter s)"
by simp_all

from discover interpret DFS_invar where s=s by simp

from discover have NE[simp]: "stack s ≠ []" by simp
note TDI = ‹tree_discovered_inv s›[unfolded tree_discovered_inv_def]

have "tree_edges s' = {} ⟶ dom (discovered s') ⊆ V0 ∧ (stack s' = [] ∨ (∃v0∈V0. stack s' = [v0]))"
by simp ― ‹@{text "tree_edges s' ≠ {}"}›

moreover {
fix x
assume A: "x ∈ (tree_edges s')⇧+ `` V0 ∪ V0" "x ∉ V0"
then obtain y where y: "(y,x) ∈ (tree_edges s')⇧+" "y ∈ V0" by auto

have "x ∈ dom (discovered s') ∪ V0"
proof (cases "tree_edges s = {}")
case True with discover A have "(tree_edges s')⇧+ = {(hd (stack s), v)}"
with A show ?thesis by auto
next
case False note t_ne = this

show ?thesis
proof (cases "x = v")
case True thus ?thesis by simp
next
case False with y have "(y,x) ∈ (tree_edges s)⇧+"
proof (induct rule: trancl_induct)
case (step a b) hence "(a,b) ∈ tree_edges s" by simp
with tree_edge_imp_discovered have "a ∈ dom (discovered s)" by simp
with discover have "a ≠ v" by blast
with step show ?case by auto
qed simp
with ‹y ∈ V0› have "x ∈ (tree_edges s)⇧+ `` V0" by auto
with t_ne TDI show ?thesis by auto
qed
qed
} note t_d = this

{
fix x
assume "x ∈ dom (discovered s') ∪ V0" "x ∉ V0"
hence A: "x ∈ dom (discovered s')" by simp

have "x ∈ (tree_edges s')⇧+ `` V0 ∪ V0"
proof (cases "tree_edges s = {}")
case True with trancl_single have "(tree_edges s')⇧+ = {(hd (stack s), v)}" by simp
moreover from True TDI have "hd (stack s) ∈ V0" "dom (discovered s) ⊆ V0" by auto
ultimately show ?thesis using A ‹x∉V0› by auto
next
case False note t_ne = this

show ?thesis
proof (cases "x=v")
case False with A have "x ∈ dom (discovered s)" by simp
with TDI t_ne ‹x ∉ V0› have "x ∈ (tree_edges s)⇧+ `` V0" by auto
with trancl_sub_insert_trancl show ?thesis by simp blast
next
case True
from t_ne TDI have "dom (discovered s) ∪ V0 = (tree_edges s)⇧+ `` V0 ∪ V0"
by simp

moreover from stack_is_tree_path[OF NE] obtain v0 where "v0 ∈ V0" and
"(v0, hd (stack s)) ∈ (tree_edges s)⇧*"
by (blast intro!: path_is_rtrancl)
with EQ have "(v0, hd (stack s)) ∈ (tree_edges s')⇧*" by (auto intro: rtrancl_mono_mp)
ultimately show ?thesis using ‹v0 ∈ V0› True by (auto elim: rtrancl_into_trancl1)
qed
qed
} with t_d have "(tree_edges s')⇧+ `` V0 ∪ V0 = dom (discovered s') ∪ V0" by blast

ultimately show ?case by (simp add: tree_discovered_inv_def)

lemmas (in DFS_invar) tree_discovered_inv =
i_tree_discovered_inv[THEN make_invar_thm]

lemma (in DFS_invar) discovered_iff_tree_path:
"v ∉ V0 ⟹ v ∈ dom (discovered s) ⟷ (∃v0∈V0. (v0,v) ∈ (tree_edges s)⇧+)"
using tree_discovered_inv

lemma i_tree_one_predecessor:
"is_invar (λs. ∀(v,v') ∈ tree_edges s. ∀y. y ≠ v ⟶ (y,v') ∉ tree_edges s)"
proof (induct rule: is_invarI)
case (discover s s' u v)
hence EQ[simp]: "tree_edges s' = insert (hd (stack s),v) (tree_edges s)" by simp

from discover interpret DFS_invar where s=s by simp
from discover have NE[simp]: "stack s ≠ []" by (simp add: cond_alt)

{
fix w w' y
assume *: "(w,w') ∈ tree_edges s'"
and  "y ≠ w"

from discover stack_discovered have v_hd: "hd (stack s) ≠ v"
using hd_in_set[OF NE] by blast
from discover tree_edges_discovered have
v_notin_tree: "∀(x,x') ∈ tree_edges s. x ≠ v ∧ x' ≠ v"
by (blast intro!: Field_not_elem)

have "(y,w') ∉ tree_edges s'"
proof (cases "w = hd (stack s)")
case True
have "(y,v) ∉ tree_edges s'"
proof (rule notI)
assume "(y,v) ∈ tree_edges s'"
with True ‹y≠w› have "(y,v) ∈ tree_edges s" by simp
with v_notin_tree show False by auto
qed
with True * ‹y≠w› v_hd show ?thesis
apply (cases "w = v")
apply simp
using discover apply simp apply blast
done
next
case False with v_notin_tree * ‹y≠w› v_hd
show ?thesis
apply (cases "w' = v")
apply simp apply blast
using discover apply simp apply blast
done
qed
}
thus ?case by blast
qed simp_all

lemma (in DFS_invar) tree_one_predecessor:
assumes "(v,w) ∈ tree_edges s"
and "a ≠ v"
shows "(a,w) ∉ tree_edges s"
using assms make_invar_thm[OF i_tree_one_predecessor]
by blast

lemma (in DFS_invar) tree_eq_rule:
"⟦(v,w) ∈ tree_edges s; (u,w) ∈ tree_edges s⟧ ⟹ v=u"
using tree_one_predecessor
by blast

context begin interpretation timing_syntax .

lemma i_tree_edge_disc:
"is_invar (λs. ∀(v,v') ∈ tree_edges s. δ s v < δ s v')"
proof (induct rule: is_invarI)
case (discover s s' u v)
hence EQ[simp]: "tree_edges s' = insert (hd (stack s), v) (tree_edges s)"
"discovered s' = (discovered s)(v ↦ counter s)"
by simp_all

from discover interpret DFS_invar where s=s by simp
from discover have NE[simp]: "stack s ≠ []" by (simp add: cond_alt)

from discover tree_edges_discovered have
v_notin_tree: "∀(x,x') ∈ tree_edges s. x ≠ v ∧ x' ≠ v"
by (blast intro!: Field_not_elem)
from discover stack_discovered have
v_hd: "hd (stack s) ≠ v"
using hd_in_set[OF NE]
by blast

{
fix a b
assume T: "(a,b) ∈ tree_edges s'"
have "δ s' a < δ s' b"
proof (cases "b = v")
case True with T v_notin_tree have [simp]: "a = hd (stack s)" by auto
with stack_discovered have "a ∈ dom (discovered s)"
by (metis hd_in_set NE subsetD)
with v_hd True timing_less_counter show ?thesis by simp
next
case False with v_notin_tree T have "(a,b) ∈ tree_edges s" "a ≠ v" by auto
with discover have "δ s a < δ s b" by auto
with False ‹a≠v› show ?thesis by simp
qed
} thus ?case by blast
next
case (new_root s s' v0) then interpret DFS_invar where s=s by simp
from new_root have "tree_edges s' = tree_edges s" by simp
moreover from tree_edge_imp_discovered new_root have "∀(v,v') ∈ tree_edges s. v ≠ v0 ∧ v' ≠ v0" by blast
ultimately show ?case using new_root by auto
qed simp_all
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemma tree_edge_disc:
"(v,w) ∈ tree_edges s ⟹ δ s v < δ s w"
using i_tree_edge_disc[THEN make_invar_thm]
by blast

lemma tree_path_disc:
"(v,w) ∈ (tree_edges s)⇧+ ⟹ δ s v < δ s w"
by (auto elim!: trancl_induct dest: tree_edge_disc)

lemma no_loop_in_tree:
"(v,v) ∉ (tree_edges s)⇧+"
using tree_path_disc by auto

lemma tree_acyclic:
"acyclic (tree_edges s)"
by (metis acyclicI no_loop_in_tree)

lemma no_self_loop_in_tree:
"(v,v) ∉ tree_edges s"
using tree_edge_disc by auto

lemma tree_edge_unequal:
"(v,w) ∈ tree_edges s ⟹ v ≠ w"
by (metis no_self_loop_in_tree)

lemma tree_path_unequal:
"(v,w) ∈ (tree_edges s)⇧+ ⟹ v ≠ w"
by (metis no_loop_in_tree)

lemma tree_subpath':
assumes x: "(x,v) ∈ (tree_edges s)⇧+"
and y: "(y,v) ∈ (tree_edges s)⇧+"
and "x ≠ y"
shows "(x,y) ∈ (tree_edges s)⇧+ ∨ (y,x) ∈ (tree_edges s)⇧+"
proof -
from x obtain px where px: "path (tree_edges s) x px v" and "px ≠ []"
using trancl_is_path by metis
from y obtain py where py: "path (tree_edges s) y py v" and "py ≠ []"
using trancl_is_path by metis

from ‹px ≠ []› ‹py ≠ []› px py
show ?thesis
proof (induction arbitrary: v rule: rev_nonempty_induct2')
case (single) hence "(x,v) ∈ tree_edges s" "(y,v) ∈ tree_edges s"
with tree_eq_rule have "x=y" by simp
with ‹x≠y› show ?case by contradiction
next
case (snocl a as) hence "(y,v) ∈ tree_edges s" by (simp add: path_simps)
moreover from snocl have "path (tree_edges s) x as a" "(a,v) ∈ tree_edges s"
ultimately have "path (tree_edges s) x as y"
using tree_eq_rule
by auto
with path_is_trancl ‹as ≠ []› show ?case by metis
next
case (snocr _ a as) hence "(x,v) ∈ tree_edges s" by (simp add: path_simps)
moreover from snocr have "path (tree_edges s) y as a" "(a,v) ∈ tree_edges s"
ultimately have "path (tree_edges s) y as x"
using tree_eq_rule
by auto
with path_is_trancl ‹as ≠ []› show ?case by metis
next
case (snoclr a as b bs) hence
"path (tree_edges s) x as a" "(a,v) ∈ tree_edges s"
"path (tree_edges s) y bs b" "(b,v) ∈ tree_edges s"
moreover hence "a=b"  using tree_eq_rule by simp
ultimately show ?thesis using snoclr.IH by metis
qed
qed

lemma tree_subpath:
assumes "(x,v) ∈ (tree_edges s)⇧+"
and "(y,v) ∈ (tree_edges s)⇧+"
and δ: "δ s x < δ s y"
shows "(x,y) ∈ (tree_edges s)⇧+"
proof -
from δ have "x ≠ y" by auto
with assms tree_subpath' have "(x,y) ∈ (tree_edges s)⇧+ ∨ (y,x) ∈ (tree_edges s)⇧+"
by simp
moreover from δ tree_path_disc have "(y,x) ∉ (tree_edges s)⇧+" by force
ultimately show ?thesis by simp
qed

lemma on_stack_is_tree_path:
assumes x: "x ∈ set (stack s)"
and y: "y ∈ set (stack s)"
and δ: "δ s x < δ s y"
shows "(x,y) ∈ (tree_edges s)⇧+"
proof -
from x obtain i where i: "stack s ! i = x" "i < length (stack s)"
by (metis in_set_conv_nth)

from y obtain j where j: "stack s ! j = y" "j < length (stack s)"
by (metis in_set_conv_nth)

with i δ stack_nth_order have "j < i" by force

from x have ne[simp]: "stack s ≠ []" by auto

from ‹j<i› have "x ∈ set (tl (stack s))"
using nth_mem nth_tl[OF ne, of "i - 1"] i
by auto
with tl_stack_hd_tree_path have
x_path: "(x, hd (stack s)) ∈ (tree_edges s)⇧+"
by simp

then show ?thesis
proof (cases "j=0")
case True with j have "hd (stack s) = y" by (metis hd_conv_nth ne)
with x_path show ?thesis by simp
next
case False hence "y ∈ set (tl (stack s))"
using nth_mem nth_tl[OF ne, of "j - 1"] j
by auto
with tl_stack_hd_tree_path have "(y, hd (stack s)) ∈ (tree_edges s)⇧+"
by simp
with x_path δ show ?thesis
using tree_subpath
by metis
qed
qed

lemma hd_stack_tree_path_finished:
assumes "stack s ≠ []"
assumes "(hd (stack s), v) ∈ (tree_edges s)⇧+"
shows "v ∈ dom (finished s)"
proof (cases "v ∈ set (stack s)")
case True
from assms no_loop_in_tree have "hd (stack s) ≠ v" by auto
with True have "v ∈ set (tl (stack s))" by (cases "stack s") auto
with tl_stack_hd_tree_path assms have "(hd (stack s), hd (stack s)) ∈ (tree_edges s)⇧+" by (metis trancl_trans)
with no_loop_in_tree show ?thesis by contradiction
next
case False
from assms obtain x where "(x,v) ∈ tree_edges s" by (metis tranclE)
with tree_edge_imp_discovered have "v ∈ dom (discovered s)" by blast
with False show ?thesis by (simp add: stack_set_def)
qed

lemma tree_edge_impl_parenthesis:
assumes t: "(v,w) ∈ tree_edges s"
and f: "v ∈ dom (finished s)"
shows "w ∈ dom (finished s)
∧ δ s v < δ s w
∧ φ s w < φ s v "
proof -
from tree_edge_disc_lt_fin assms have "δ s w < φ s v" by simp
with f tree_edge_imp_discovered[OF t] tree_edge_disc[OF t]
show ?thesis
using parenthesis_contained
by metis
qed

lemma tree_path_impl_parenthesis:
assumes "(v,w) ∈ (tree_edges s)⇧+"
and "v ∈ dom (finished s)"
shows "w ∈ dom (finished s)
∧ δ s v < δ s w
∧ φ s w < φ s v "
using assms
by (auto elim!: trancl_induct dest: tree_edge_impl_parenthesis)

lemma nc_reachable_v0_parenthesis:
assumes C: "¬ cond s" "¬ is_break param s"
and v: "v ∈ reachable" "v ∉ V0"
obtains v0 where "v0 ∈ V0"
and "δ s v0 < δ s v ∧ φ s v < φ s v0 "
proof -
from nc_discovered_eq_reachable[OF C] discovered_iff_tree_path v
obtain v0 where "v0 ∈ V0" and
"(v0,v) ∈ (tree_edges s)⇧+"
by auto
moreover with nc_V0_finished[OF C] have "v0 ∈ dom (finished s)"
by auto
ultimately show ?thesis
using tree_path_impl_parenthesis that[OF ‹v0 ∈ V0›]
by simp
qed

end end

context param_DFS begin context begin interpretation timing_syntax .

definition paren_imp_tree_reach where
"paren_imp_tree_reach s ≡ ∀v ∈ dom (discovered s). ∀w ∈ dom (finished s).
δ s v < δ s w ∧ (v ∉ dom (finished s) ∨ φ s v > φ s w)
⟶ (v,w) ∈ (tree_edges s)⇧+"

lemma paren_imp_tree_reach:
"is_invar paren_imp_tree_reach"
unfolding paren_imp_tree_reach_def[abs_def]
proof (induct rule: is_invarI)
case (discover s s' u v)
hence EQ[simp]: "tree_edges s' = insert (hd (stack s), v) (tree_edges s)"
"finished s' = finished s"
"discovered s' = (discovered s)(v ↦ counter s)"
by simp_all

from discover interpret DFS_invar where s=s by simp
from discover have NE[simp]: "stack s ≠ []" by (simp add: cond_alt)

show ?case
proof (intro ballI impI)
fix a b
assume F:"a ∈ dom (discovered s')" "b ∈ dom (finished s')"
and D: "δ s' a < δ s' b ∧ (a ∉ dom (finished s') ∨ φ s' a > φ s' b)"

from F finished_discovered discover have "b ≠ v" by auto
show "(a,b) ∈ (tree_edges s')⇧+"
proof (cases "a = v")
case True with D ‹b≠v› have "counter s < δ s b" by simp
also from F have "b ∈ dom (discovered s)"
using finished_discovered by auto
with timing_less_counter have "δ s b < counter s" by simp
finally have False .
thus ?thesis ..
next
case False with ‹b≠v› F D discover have "(a,b) ∈ (tree_edges s)⇧+" by simp
thus ?thesis by (auto intro: trancl_mono_mp)
qed
qed
next
case (finish s s' u)
hence EQ[simp]: "tree_edges s' = tree_edges s"
"finished s' = (finished s)(hd (stack s) ↦ counter s)"
"discovered s' = discovered s"
"stack s' = tl (stack s)"
by simp_all

from finish interpret DFS_invar where s=s by simp
from finish have NE[simp]: "stack s ≠ []" by (simp add: cond_alt)

show ?case
proof (intro ballI impI)
fix a b
assume F: "a ∈ dom (discovered s')" "b ∈ dom (finished s')"
and paren: "δ s' a < δ s' b ∧ (a ∉ dom (finished s') ∨ φ s' a > φ s' b)"
hence "a ≠ b" by auto

show "(a,b) ∈ (tree_edges s')⇧+"
proof (cases "b = hd (stack s)")
case True hence φb: "φ s' b = counter s" by simp
have "a ∈ set (stack s)"
unfolding stack_set_def
proof
from F show "a ∈ dom (discovered s)" by simp
from True ‹a≠b› φb paren have "a ∈ dom (finished s) ⟶ φ s a > counter s" by simp
with timing_less_counter show "a ∉ dom (finished s)" by force
qed
with paren True on_stack_is_tree_path have "(a,b) ∈ (tree_edges s)⇧+" by auto
thus ?thesis by (auto intro: trancl_mono_mp)
next
case False note b_not_hd = this
show ?thesis
proof (cases "a = hd (stack s)")
case False with b_not_hd F paren finish show ?thesis by simp
next
case True with paren b_not_hd F have
"a ∈ dom (discovered s)" "b ∈ dom (finished s)"  "δ s a < δ s b"
by simp_all
moreover from True stack_not_finished have "a ∉ dom (finished s)"
by simp
ultimately show ?thesis by (simp add: finish)
qed
qed
qed
next
case (new_root s s' v0) then interpret DFS_invar where s=s by simp
from new_root finished_discovered have "v0 ∉ dom (finished s)" by auto
moreover note timing_less_counter finished_discovered
ultimately show ?case using new_root by clarsimp force
qed simp_all
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemmas s_paren_imp_tree_reach =
paren_imp_tree_reach[THEN make_invar_thm]

lemma parenthesis_impl_tree_path_not_finished:
assumes "v ∈ dom (discovered s)"
and "w ∈ dom (finished s)"
and "δ s v < δ s w"
and "v ∉ dom (finished s)"
shows "(v,w) ∈ (tree_edges s)⇧+"
using s_paren_imp_tree_reach assms

lemma parenthesis_impl_tree_path:
assumes "v ∈ dom (finished s)" "w ∈ dom (finished s)"
and "δ s v < δ s w" "φ s v > φ s w"
shows "(v,w) ∈ (tree_edges s)⇧+"
proof -
from assms(1) have "v ∈ dom (discovered s)"
using finished_discovered by blast
with assms show ?thesis
using s_paren_imp_tree_reach assms
qed

lemma tree_path_iff_parenthesis:
assumes "v ∈ dom (finished s)" "w ∈ dom (finished s)"
shows "(v,w) ∈ (tree_edges s)⇧+ ⟷ δ s v < δ s w ∧ φ s v > φ s w"
using assms
by (metis parenthesis_impl_tree_path tree_path_impl_parenthesis)

lemma no_pending_succ_impl_path_in_tree:
assumes v: "v ∈ dom (discovered s)" "pending s `` {v} = {}"
and w: "w ∈ succ v"
and δ: "δ s v < δ s w"
shows "(v,w) ∈ (tree_edges s)⇧+"
proof (cases "v ∈ dom (finished s)")
case True
with assms assms have "δ s w < φ s v" "w ∈ dom (discovered s)"
using finished_succ_fin finished_imp_succ_discovered
by simp_all
with True δ show ?thesis
using parenthesis_contained parenthesis_impl_tree_path
by blast
next
case False
show ?thesis
proof (cases "w ∈ dom (finished s)")
case True with False v δ show ?thesis by (simp add: parenthesis_impl_tree_path_not_finished)
next
case False with ‹v ∉ dom (finished s)› no_pending_imp_succ_discovered v w have
"v ∈ set (stack s)" "w ∈ set (stack s)"
with on_stack_is_tree_path δ show ?thesis by simp
qed
qed

lemma finished_succ_impl_path_in_tree:
assumes f:  "v ∈ dom (finished s)"
and s: "w ∈ succ v"
and δ: "δ s v < δ s w"
shows "(v,w) ∈ (tree_edges s)⇧+"
using no_pending_succ_impl_path_in_tree finished_no_pending finished_discovered
using assms
by blast
end end

subsubsection ‹Properties of Cross Edges›
(* Cross Edges *)
context param_DFS begin context begin interpretation timing_syntax .

lemma i_cross_edges_finished: "is_invar (λs. ∀(u,v)∈cross_edges s.
v ∈ dom (finished s) ∧ (u ∈ dom (finished s) ⟶ φ s v < φ s u))"
proof (induction rule: is_invarI_full)
case (finish s s' u e)
interpret DFS_invar G param s by fact
from finish stack_not_finished have "u ∉ dom (finished s)" by auto
with finish show ?case by (auto intro: timing_less_counter)
next
case (cross_edge s s' u v e)
interpret DFS_invar G param s by fact
from cross_edge stack_not_finished have "u ∉ dom (finished s)" by auto
with cross_edge show ?case by (auto intro: timing_less_counter)
qed simp_all

end end

context DFS_invar begin context begin interpretation timing_syntax .
lemmas cross_edges_finished
= i_cross_edges_finished[THEN make_invar_thm]

lemma cross_edges_target_finished:
"(u,v)∈cross_edges s ⟹ v ∈ dom (finished s)"
using cross_edges_finished by auto

lemma cross_edges_finished_decr:
"⟦(u,v)∈cross_edges s; u∈dom (finished s)⟧ ⟹ φ s v < φ s u"
using cross_edges_finished by auto

lemma cross_edge_unequal:
assumes cross: "(v,w) ∈ cross_edges s"
shows "v ≠ w"
proof -
from cross_edges_target_finished[OF cross] have
w_fin: "w ∈ dom (finished s)" .

show ?thesis
proof (cases "v ∈ dom (finished s)")
case True with cross_edges_finished_decr[OF cross]
show ?thesis by force
next
case False with w_fin show ?thesis by force
qed
qed
end end

subsubsection ‹Properties of Back Edges›
(* Back Edges *)
context param_DFS begin context begin interpretation timing_syntax .

lemma i_back_edge_impl_tree_path:
"is_invar (λs. ∀(v,w) ∈ back_edges s. (w,v) ∈ (tree_edges s)⇧+ ∨ w = v)"
proof (induct rule: is_invarI_full)
case (back_edge s s' u v) then interpret DFS_invar where s=s by simp

from back_edge have st: "v ∈ set (stack s)" "u ∈ set (stack s)"
using stack_set_def
by auto

have "(v,u) ∈ (tree_edges s)⇧+ ∨ u = v"
proof (rule disjCI)
assume "u ≠ v"
with st back_edge have "v ∈ set (tl (stack s))" by (metis not_hd_in_tl)
with tl_lt_stack_hd_discover st back_edge have "δ s v < δ s u" by simp
with on_stack_is_tree_path st show "(v,u) ∈ (tree_edges s)⇧+" by simp
qed
with back_edge show ?case by auto
next
case discover thus ?case using trancl_sub_insert_trancl by force
qed simp_all

end end

context DFS_invar begin context begin interpretation timing_syntax .

lemma back_edge_impl_tree_path:
"⟦(v,w) ∈ back_edges s; v ≠ w⟧ ⟹ (w,v) ∈ (tree_edges s)⇧+"
using i_back_edge_impl_tree_path[THEN make_invar_thm]
by blast

lemma back_edge_disc:
assumes "(v,w) ∈ back_edges s"
shows "δ s w ≤ δ s v"
proof cases
assume "v≠w"
with assms back_edge_impl_tree_path have "(w,v) ∈ (tree_edges s)⇧+" by simp
with tree_path_disc show ?thesis by force
qed simp

lemma back_edges_tree_disjoint:
"back_edges s ∩ tree_edges s = {}"
using back_edge_disc tree_edge_disc
by force

lemma back_edges_tree_pathes_disjoint:
"back_edges s ∩ (tree_edges s)⇧+ = {}"
using back_edge_disc tree_path_disc
by force

lemma back_edge_finished:
assumes "(v,w) ∈ back_edges s"
and "w ∈ dom (finished s)"
shows "v ∈ dom (finished s) ∧ φ s v ≤ φ s w"
proof (cases "v=w")
case True with assms show ?thesis by simp
next
case False with back_edge_impl_tree_path assms have "(w,v) ∈ (tree_edges s)⇧+" by simp
with tree_path_impl_parenthesis assms show ?thesis by fastforce
qed

end end

context param_DFS begin context begin interpretation timing_syntax .
(* The lemma should probably replaced by:
is_invar (λs. ∀(v,w) ∈ (tree_edges s)⇧+. v ∈ succ w ⟶ (w,v) ∈ back_edges s ∨ (w,v) ∈ pending s)
*)
lemma i_disc_imp_back_edge_or_pending:
"is_invar (λs. ∀(v,w) ∈ E.
v ∈ dom (discovered s) ∧ w ∈ dom (discovered s)
∧ δ s v ≥ δ s w
∧ (w ∈ dom (finished s) ⟶ v ∈ dom (finished s) ∧ φ s w ≥ φ s v)
⟶ (v,w) ∈ back_edges s ∨ (v,w) ∈ pending s)"
proof (induct rule: is_invarI_full)
case (cross_edge s s' u v) then interpret DFS_invar where s=s by simp
from cross_edge stack_not_finished[of u] have "u ∉ dom (finished s)"
using hd_in_set
with cross_edge show ?case by auto
next
case (finish s s' u v) then interpret DFS_invar where s=s by simp

from finish have
IH: "⋀v w. ⟦w ∈ succ v; v ∈ dom (discovered s); w ∈ dom (discovered s);
δ s w ≤ δ s v;
(w ∈ dom (finished s) ⟹ v ∈ dom (finished s) ∧ φ s v ≤ φ s w)⟧
⟹ (v, w) ∈ back_edges s ∨ (v, w) ∈ pending s"
by blast

from finish have ne[simp]: "stack s ≠ []"
and p[simp]: "pending s `` {hd (stack s)} = {}"
by (simp_all)

from hd_in_set[OF ne] have disc: "hd (stack s) ∈ dom (discovered s)"
and not_fin: "hd (stack s) ∉ dom (finished s)"
using stack_discovered stack_not_finished
by blast+

{
fix w
assume w: "w ∈ succ (hd (stack s))" "w ≠ hd (stack s)" "w ∈ dom (discovered s)"
and f: "w ∈ dom (finished s) ⟶ counter s ≤ φ s w"
and δ: "δ s w ≤ δ s (hd (stack s))"

with timing_less_counter have "w ∉ dom (finished s)" by force
with finish w δ disc have "(hd (stack s), w) ∈ back_edges s" by blast
}

moreover
{
fix w
assume "hd (stack s) ∈ succ w" "w ≠ hd (stack s)"
and "w ∈ dom (finished s)" "δ s (hd (stack s)) ≤ δ s w"
with IH[of "hd (stack s)" w] disc not_fin have
"(w, hd (stack s)) ∈ back_edges s"
using finished_discovered finished_no_pending[of w]
by blast
}

ultimately show ?case
using finish
by clarsimp auto
next
case (discover s s' u v) then interpret DFS_invar where s=s by simp

from discover show ?case
using timing_less_counter
by clarsimp fastforce
next
case (new_root s s' v0) then interpret DFS_invar where s=s by simp

from new_root empty_stack_imp_empty_pending have "pending s = {}" by simp
with new_root show ?case
using timing_less_counter
by clarsimp fastforce
qed auto
end end

context DFS_invar begin context begin interpretation timing_syntax .

lemma disc_imp_back_edge_or_pending:
"⟦w ∈ succ v; v ∈ dom (discovered s); w ∈ dom (discovered s); δ s w ≤ δ s v;
(w ∈ dom (finished s) ⟹ v ∈ dom (finished s) ∧ φ s v ≤ φ s w)⟧
⟹ (v, w) ∈ back_edges s ∨ (v, w) ∈ pending s"
using i_disc_imp_back_edge_or_pending[THEN make_invar_thm]
by blast

lemma finished_imp_back_edge:
"⟦w ∈ succ v; v ∈ dom (finished s); w ∈ dom (finished s);
δ s w ≤ δ s v; φ s v ≤ φ s w⟧
⟹ (v, w) ∈ back_edges s"
using disc_imp_back_edge_or_pending finished_discovered finished_no_pending
by fast

lemma finished_not_finished_imp_back_edge:
"⟦w ∈ succ v; v ∈ dom (finished s); w ∈ dom (discovered s);
w ∉ dom (finished s);
δ s w ≤ δ s v⟧
⟹ (v, w) ∈ back_edges s"
using disc_imp_back_edge_or_pending finished_discovered finished_no_pending
by fast

lemma finished_self_loop_in_back_edges:
assumes "v ∈ dom (finished s)"
and "(v,v) ∈ E"
shows "(v,v) ∈ back_edges s"
using assms
using finished_imp_back_edge
by blast
end end

(* Back edges and Cycles *)

context DFS_invar begin

context begin interpretation timing_syntax .
(* Cross and tree_edges edges are always acyclic *)
lemma tree_cross_acyclic:
"acyclic (tree_edges s ∪ cross_edges s)" (is "acyclic ?E")
proof (rule ccontr)
{
fix u v
assume *: "u ∈ dom (finished s)" and "(u,v) ∈ ?E⇧+"
from this(2) have "φ s v < φ s u ∧ v ∈ dom (finished s)"
proof induct
case base thus ?case
by (metis Un_iff * cross_edges_finished_decr cross_edges_target_finished tree_edge_impl_parenthesis)
next
case (step v w)
hence "φ s w < φ s v ∧ w ∈ dom (finished s)"
by (metis Un_iff cross_edges_finished_decr cross_edges_target_finished tree_edge_impl_parenthesis)
with step show ?case by auto
qed
} note aux = this

assume "¬ acyclic ?E"
then obtain u where path: "(u,u) ∈ ?E⇧+" by (auto simp add: acyclic_def)
show False
proof cases
assume "u ∈ dom (finished s)"
with aux path show False by blast
next
assume *: "u ∉ dom (finished s)"
moreover
from no_loop_in_tree have "(u,u) ∉ (tree_edges s)⇧+" .
with trancl_union_outside[OF path] obtain x y where "(u,x) ∈ ?E⇧*" "(x,y) ∈ cross_edges s" "(y,u) ∈ ?E⇧*" by auto
with cross_edges_target_finished have "y ∈ dom (finished s)" by simp
moreover with * ‹(y,u) ∈ ?E⇧*› have "(y,u) ∈ ?E⇧+" by (auto simp add: rtrancl_eq_or_trancl)
ultimately show False by (metis aux)
qed
qed
end

lemma cycle_contains_back_edge:
assumes cycle: "(u,u) ∈ (edges s)⇧+"
shows "∃v w. (u,v) ∈ (edges s)⇧* ∧ (v,w) ∈ back_edges s ∧ (w,u) ∈ (edges s)⇧*"
proof -
from tree_cross_acyclic have "(u,u) ∉ (tree_edges s ∪ cross_edges s)⇧+" by (simp add: acyclic_def)
with trancl_union_outside[OF cycle] show ?thesis .
qed

lemma cycle_needs_back_edge:
assumes "back_edges s = {}"
shows "acyclic (edges s)"
proof (rule ccontr)
assume "¬ acyclic (edges s)"
then obtain u where "(u,u) ∈ (edges s)⇧+" by (auto simp: acyclic_def)
with assms have "(u,u) ∈ (tree_edges s ∪ cross_edges s)⇧+" by auto
with tree_cross_acyclic show False by (simp add: acyclic_def)
qed

lemma back_edge_closes_cycle:
assumes "back_edges s ≠ {}"
shows "¬ acyclic (edges s)"
proof -
from assms obtain v w where be: "(v,w) ∈ back_edges s" by auto
hence "(w,w) ∈ (edges s)⇧+"
proof (cases "v=w")
case False
with be back_edge_impl_tree_path have "(w,v) ∈ (tree_edges s)⇧+" by simp
hence "(w,v) ∈ (edges s)⇧+" by (blast intro: trancl_mono_mp)
also from be have "(v,w) ∈ edges s" by simp
finally show ?thesis .
qed auto
thus ?thesis by (auto simp add: acyclic_def)
qed

lemma back_edge_closes_reachable_cycle:
"back_edges s ≠ {} ⟹ ¬ acyclic (E ∩ reachable × UNIV)"
by (metis back_edge_closes_cycle edges_ss_reachable_edges cyclic_subset)

lemma cycle_iff_back_edges:
"acyclic (edges s) ⟷ back_edges s = {}"
by (metis back_edge_closes_cycle cycle_needs_back_edge)
end

subsection ‹White Path Theorem›

context DFS begin
context begin interpretation timing_syntax .

definition white_path where
"white_path s x y ≡ x≠y
⟶ (∃p. path E x p y ∧
(δ s x < δ s y ∧ (∀ v ∈ set (tl p). δ s x < δ s v)))"

lemma white_path:
"it_dfs ≤ SPEC(λs. ∀x ∈ reachable. ∀y ∈ reachable. ¬ is_break param s ⟶
white_path s x y ⟷ (x,y) ∈ (tree_edges s)⇧*)"
proof (rule it_dfs_SPEC, intro ballI impI)
fix s x y
assume DI: "DFS_invar G param s"
and C: "¬ cond s" "¬ is_break param s"
and reach: "x ∈ reachable" "y ∈ reachable"

from DI interpret DFS_invar where s=s .

note fin_eq_reach = nc_finished_eq_reachable[OF C]

show "white_path s x y ⟷ (x,y) ∈ (tree_edges s)⇧*"
proof (cases "x=y")
case True thus ?thesis by (simp add: white_path_def)
next
case False

show ?thesis
proof
assume "(x,y) ∈ (tree_edges s)⇧*"
with ‹x≠y› have T: "(x,y) ∈ (tree_edges s)⇧+" by (metis rtranclD)
then obtain p where P: "path (tree_edges s) x p y" by (metis trancl_is_path)
with tree_edges_ssE have "path E x p y" using path_mono[where E="tree_edges s"]
by simp
moreover
from P have "δ s x < δ s y ∧ (∀ v ∈ set (tl p). δ s x < δ s v)"
using ‹x≠y›
proof (induct rule: path_tl_induct)
case (single u) thus ?case by (fact tree_edge_disc)
next
case (step u v) note ‹δ s x < δ s u›
also from step have "δ s u < δ s v" by (metis tree_edge_disc)
finally show ?case .
qed
ultimately show "white_path s x y"
by (auto simp add: ‹x≠y› white_path_def)
next
assume "white_path s x y"
with ‹x≠y› obtain p where
P:"path E x p y" and
white: "δ s x < δ s y ∧ (∀ v ∈ set (tl p). δ s x < δ s v)"
unfolding white_path_def
by blast
hence "p ≠ []" by auto
thus "(x,y) ∈ (tree_edges s)⇧*" using P white reach(2)
proof (induction p arbitrary: y rule: rev_nonempty_induct)
case single hence "y ∈ succ x" by (simp add: path_cons_conv)
with reach single show ?case
using fin_eq_reach finished_succ_impl_path_in_tree[of x y]
by simp
next
case (snoc u us) hence "path E x us u" by (simp add: path_append_conv)
moreover hence "(x,u) ∈ E⇧*" by (simp add: path_is_rtrancl)
with reach have ureach: "u ∈ reachable"
moreover from snoc have "δ s x < δ s u" "(∀v∈set (tl us). δ s x < δ s v)"
by simp_all
ultimately have x_u: "(x,u) ∈ (tree_edges s)⇧*" by (metis snoc.IH)

from snoc have "y ∈ succ u" by (simp add: path_append_conv)
from snoc(5) fin_eq_reach finished_discovered have
y_f_d: "y ∈ dom (finished s)" "y ∈ dom (discovered s)"
by auto

from ‹y ∈ succ u› ureach fin_eq_reach have "δ s y < φ s u"
using finished_succ_fin by simp
also from ‹δ s x < δ s u› have "x ≠ u" by auto
with x_u have "(x,u) ∈ (tree_edges s)⇧+" by (metis rtrancl_eq_or_trancl)
with fin_eq_reach reach have "φ s u < φ s x"
using tree_path_impl_parenthesis
by simp
finally have "φ s y < φ s x"
using reach fin_eq_reach y_f_d snoc
using parenthesis_contained
by blast
hence "(x,y) ∈ (tree_edges s)⇧+"
using reach fin_eq_reach y_f_d snoc
using parenthesis_impl_tree_path
by blast
thus ?case by auto
qed
qed
qed
qed
end end

end
```