Theory Undirected_Graph_Theory.Undirected_Graph_Walks

theory Undirected_Graph_Walks imports Undirected_Graph_Basics
begin

section ‹Walks, Paths and Cycles ›
text ‹ The definition of walks, paths, cycles, and related concepts are foundations of graph theory,
yet there can be some differences in literature between definitions. This formalisation draws inspiration 
from Noschinski's Graph Library cite"noschinski_2015", however focuses on an undirected graph context
compared to a directed graph context, and extends on some definitions, as required to formalise
Balog Szemeredi Gowers theorem. ›

context ulgraph
begin

subsection ‹ Walks›

text‹This definition is taken from the directed graph library, however edges are undirected› 
fun walk_edges :: "'a list  'a edge list" where
    "walk_edges [] = []"
  | "walk_edges [x] = []"
  | "walk_edges (x # y # ys) = {x,y} # walk_edges (y # ys)"

lemma walk_edges_app: "walk_edges (xs @ [y, x]) = walk_edges (xs @ [y]) @ [{y, x}]"
  by (induct xs rule: walk_edges.induct, simp_all)

lemma walk_edges_tl_ss: "set (walk_edges (tl xs))  set (walk_edges xs)"
  by (induct xs rule: walk_edges.induct)  auto

lemma walk_edges_rev: "rev (walk_edges xs) = walk_edges (rev xs)"
proof (induct xs rule: walk_edges.induct, simp_all)
  fix x y ys assume assm: "rev (walk_edges (y # ys)) = walk_edges (rev ys @ [y])"
  then show "walk_edges (rev ys @ [y]) @ [{x, y}] = walk_edges (rev ys @ [y, x])"
    using walk_edges_app by fastforce 
qed

lemma walk_edges_append_ss1: "set (walk_edges (ys))  set (walk_edges (xs@ys))"
proof (induct xs rule: walk_edges.induct)
  case 1
  then show ?case by simp
next
  case (2 x)
  then show ?case
    using walk_edges_tl_ss by fastforce 
next
  case (3 x y ys)
  then show ?case by (simp add: subset_iff) 
qed 
 

lemma walk_edges_append_ss2: "set (walk_edges (xs))  set (walk_edges (xs@ys))"
  by (induct xs rule: walk_edges.induct) auto

lemma walk_edges_singleton_app: "ys  []  walk_edges ([x]@ys) = {x, hd ys} # walk_edges ys"
  using list.exhaust_sel walk_edges.simps(3) by (metis Cons_eq_appendI eq_Nil_appendI) 

lemma walk_edges_append_union: "xs  []  ys  []  
    set (walk_edges (xs@ys)) = set (walk_edges (xs))  set (walk_edges ys)  {{last xs, hd ys}}"
  using walk_edges_singleton_app  by (induct xs rule: walk_edges.induct) auto

lemma walk_edges_decomp_ss: "set (walk_edges (xs@[y]@zs))  set (walk_edges (xs@[y]@ys@[y]@zs))"
proof -
  have half_ss: "set (walk_edges (xs@[y]))  set (walk_edges (xs@[y]@ys@[y]))" 
    using walk_edges_append_ss2 by fastforce
  thus ?thesis proof (cases "zs = []")
    case True
    then show ?thesis using half_ss by auto
  next
    case False
    then have decomp1: "set (walk_edges (xs@[y]@zs)) = set (walk_edges (xs@[y]))  set (walk_edges (zs))  {{y, hd zs}}" 
      using walk_edges_append_union
      by (metis append_assoc append_is_Nil_conv last_snoc neq_Nil_conv) 
    have "set (walk_edges (xs@[y]@ys@[y]@zs)) =  set (walk_edges (xs@[y]@ys@[y]))  set (walk_edges (zs))  {{y, hd zs}}"
      using walk_edges_append_union False
      by (metis append_assoc append_is_Nil_conv empty_iff empty_set last_snoc list.set_intros(1)) 
    then show ?thesis using decomp1 half_ss by auto
  qed
qed

definition walk_length :: "'a list  nat" where
  "walk_length p  length (walk_edges p)"

lemma walk_length_conv: "walk_length p = length p - 1"
  by (induct p rule: walk_edges.induct) (auto simp: walk_length_def)

lemma walk_length_rev: "walk_length p = walk_length (rev p)"
  using walk_edges_rev walk_length_def
  by (metis length_rev) 

lemma walk_length_app: "xs  []  ys  []  walk_length (xs @ ys) = walk_length xs + walk_length ys + 1"
  apply (induct xs rule: walk_edges.induct) 
    apply (simp_all add: walk_length_def)
  using walk_edges_singleton_app by force

lemma walk_length_app_ineq: "walk_length (xs @ ys)  walk_length xs + walk_length ys  
  walk_length (xs @ ys)  walk_length xs + walk_length ys + 1"
proof (cases "xs = []  ys = []")
  case True
  then show ?thesis using walk_length_def by auto 
next
  case False
  then show ?thesis
    by (simp add: walk_length_app) 
qed

text ‹ Note that while the trivial walk is allowed, the empty walk is not ›
definition is_walk :: "'a list  bool" where
"is_walk xs  set xs  V  set (walk_edges xs)  E  xs  []"

lemma is_walkI: "set xs  V  set (walk_edges xs)  E  xs  []  is_walk xs"
  using is_walk_def by simp 

lemma is_walk_wf: "is_walk xs  set xs  V"
  by (simp add: is_walk_def)

lemma is_walk_wf_hd: "is_walk xs  hd xs  V"
  using is_walk_wf hd_in_set is_walk_def by blast 

lemma is_walk_wf_last: "is_walk xs  last xs  V"
  using is_walk_wf last_in_set is_walk_def by blast

lemma is_walk_singleton: "u  V  is_walk [u]"
  unfolding is_walk_def using walk_edges.simps by simp

lemma is_walk_not_empty: "is_walk xs  xs  []" 
  unfolding is_walk_def by simp

lemma is_walk_not_empty2: "is_walk [] = False" 
  unfolding is_walk_def by simp

text ‹Reasoning on transformations of a walk ›
lemma is_walk_rev: "is_walk xs  is_walk (rev xs)"
  unfolding is_walk_def using walk_edges_rev
  by (metis rev_is_Nil_conv set_rev)

lemma is_walk_tl: "length xs  2  is_walk xs  is_walk (tl xs)"
  using walk_edges_tl_ss is_walk_def in_mono list.set_sel(2) tl_Nil by fastforce
 
lemma is_walk_append: 
  assumes "is_walk xs"
  assumes "is_walk ys"
  assumes "last xs = hd ys"
  shows "is_walk (xs @ (tl ys))"
proof (intro is_walkI subsetI)
  show "xs @ tl ys  []" using is_walk_def assms by auto
  show "x. x  set (xs @ tl ys)  x  V" using assms is_walk_def is_walk_wf
    by (metis Un_iff in_mono list_set_tl set_append)
next
  fix x assume xin: "x  set (walk_edges (xs @ tl ys))"
  show "x  E" proof (cases "tl ys = []")
    case True
    then show ?thesis using assms(1) is_walk_def xin by auto
  next
    case False
    then have xin2: "x  (set (walk_edges xs)  set (walk_edges (tl ys))  {{last xs, hd (tl ys)}})" 
      using walk_edges_append_union is_walk_not_empty assms xin by auto
    have 1: "set (walk_edges xs)  E" using assms(1) is_walk_def
      by simp 
    have 2: "set (walk_edges (tl ys))  E" using assms(2) is_walk_def
      by (meson dual_order.trans walk_edges_tl_ss)
    have "{last xs, hd (tl ys)}  E" using is_walk_def assms(2) assms(3)
      by (metis False hd_Cons_tl insert_subset list.simps(15) walk_edges.simps(3)) 
    then show ?thesis using 1 2 xin2 by auto
  qed
qed

lemma is_walk_decomp: 
  assumes "is_walk (xs@[y]@ys@[y]@zs)" (is "is_walk ?w")
  shows "is_walk (xs@[y]@zs)"
proof (intro is_walkI) 
  show "set (xs @ [y] @ zs)  V"  using assms is_walk_def by simp
  show "xs @ [y] @ zs  []" by simp
  show "set (walk_edges (xs @ [y] @ zs))  E" 
    using walk_edges_decomp_ss assms(1) is_walk_def by blast 
qed

lemma is_walk_hd_tl: 
  assumes "is_walk (y # ys)"
  assumes "{x, y}  E"
  shows "is_walk (x # y # ys)"
proof (intro is_walkI)
  show "set (x # y # ys)  V"
    using assms by (simp add: is_walk_def wellformed_alt_fst) 
  show "set (walk_edges (x # y # ys))  E"
    using walk_edges.simps assms is_walk_def by simp
  show "x # y # ys  []" by simp
qed

lemma is_walk_drop_hd: 
  assumes "ys  []"
  assumes "is_walk (y # ys)"
  shows "is_walk ys"
proof (intro is_walkI)
  show "set ys  V" 
    using assms is_walk_wf by fastforce
  show "set (walk_edges ys)  E"
    using assms is_walk_def walk_edges_tl_ss by force 
  show "ys  []" using assms by simp
qed

lemma walk_edges_index: 
  assumes "i  0" "i < walk_length w"
  assumes "is_walk w"
  shows "(walk_edges w) ! i  E"
  using assms 
proof (induct w arbitrary: i rule: walk_edges.induct, simp add: is_walk_not_empty2, 
    simp add: walk_length_def)
  case (3 x y ys)
  then show ?case proof (cases "i = 0")
    case True
    then show ?thesis
      using "3.prems"(3) is_walk_def by fastforce 
  next
    case False
    have gt: "0  i -1" using False by simp
    have lt: "i - 1 < walk_length (y # ys)"
      using "3.prems"(2) False walk_length_conv by auto 
    have "is_walk (y # ys)"
      using "3.prems"(3) is_walk_def by fastforce 
    then show ?thesis using "3.hyps"[of "i -1"]
      by (metis "3.prems"(1) False gt lt le_neq_implies_less nth_Cons_pos walk_edges.simps(3)) 
  qed
qed

lemma is_walk_index: 
  assumes "i  0" "Suc i < (length w)"
  assumes "is_walk w"
  shows "{w ! i, w ! (i + 1)}  E" 
  using assms proof (induct w arbitrary: i rule: walk_edges.induct, simp, simp)
  fix x y ys i
  assume IH: "j. 0  j  Suc j < length (y # ys)  is_walk (y # ys)  {(y # ys) ! j, (y # ys) ! (j + 1)}  E"
  assume 1: " 0  i" and 2: "Suc i < length (x # y # ys)" and 3: "is_walk (x # y # ys)"
  show "{(x # y # ys) ! i, (x # y # ys) ! (i + 1)}  E"
  proof (cases "i = 0")
    case True
    then show ?thesis using 3 is_walk_def
      by simp 
  next
    case False
    have "is_walk (y # ys)" using is_walk_def 3 by fastforce
    then show ?thesis using 2 IH[of "i - 1"]
      by (simp add: False nat_less_le)
  qed
qed

lemma is_walk_take: 
  assumes "is_walk w"
  assumes "n > 0"
  assumes "n  length w"
  shows "is_walk (take n w)"
  using assms proof (induct w arbitrary: n rule: walk_edges.induct)
  case 1
  then show ?case by simp 
next
  case (2 x)
  then have "n = 1" using 2 by auto
  then show ?case by (simp add: "2.prems"(1)) 
next
  case (3 x y ys)
  then show ?case proof (cases "n = 1")
    case True
    then have "take n (x # y # ys) = [x]"
      by simp 
    then show ?thesis using is_walk_def "3.prems"(1) by simp
  next
    case False
    then have ngt: "n  2" using "3.prems"(2) by auto
    then have tk_split1: "take n (x # y # ys) = x # take (n - 1) (y # ys)" using 3
      by (simp add: take_Cons') 
    then have tk_split: "take n (x # y # ys) = x # y # (take (n - 2) ys)" 
      using 3 ngt take_Cons'[of "n -1" "y" "ys"]
      by (metis False diff_diff_left less_one nat_neq_iff one_add_one zero_less_diff)  
    have w: "is_walk (y # ys)" using is_walk_tl
      using "3.prems"(1) is_walk_def by force 
    have "n - 1  length (y # ys)" using "3.prems"(3) by simp
    then have w_tl: "is_walk (take (n - 1) (y # ys))" using "3.hyps"[of "n - 1"] w "3.prems" ngt
      by linarith 
    have "{x, y}  E" using is_walk_def walk_edges.simps "3.prems"(1) by auto 
    then show ?thesis using is_walk_hd_tl[of y "(take (n - 2) ys)" x] tk_split
      using tk_split1 w_tl by force 
  qed
qed

lemma is_walk_drop: 
  assumes "is_walk w"
  assumes "n < length w"
  shows "is_walk (drop n w)"
  using assms proof (induct w arbitrary: n rule: walk_edges.induct)
  case 1
  then show ?case by simp 
next
  case (2 x)
  then have "n = 0" using 2 by auto
  then show ?case by (simp add: "2.prems"(1)) 
next
  case (3 x y ys)
  then show ?case proof (cases "n  2")
    case True
    then have ngt: "n  2" using "3.prems"(2) by auto
    then have tk_split1: "drop n (x # y # ys) = drop (n - 1) (y # ys)" using 3
      by (simp add: drop_Cons') 
    then have tk_split: "drop n (x # y # ys) = (drop (n - 2) ys)" 
      using 3 ngt drop_Cons'[of "n -1" "y" "ys"] True
      by (metis Suc_1 Suc_le_eq diff_diff_left less_not_refl nat_1_add_1 zero_less_diff) 
    have w: "is_walk (y # ys)" using is_walk_tl
      using "3.prems"(1) is_walk_def by force 
    have "n - 1 < length (y # ys)" using "3.prems"(2) by simp
    then have w_tl: "is_walk (drop (n - 1) (y # ys))" using "3.hyps"[of "n - 1"] w "3.prems" ngt
      by linarith 
    have "{x, y}  E" using is_walk_def walk_edges.simps "3.prems"(1) by auto 
    then show ?thesis using is_walk_hd_tl[of y "(take (n - 2) ys)" x] tk_split
      using tk_split1 w_tl by force 
  next 
    case False
    then have or: "n = 0  n = 1"
      by auto
    have walk: "is_walk (y # ys)" using is_walk_drop_hd 3 by blast 
    have n0: "n = 0  (drop n (x # y # ys)) = (x # y # ys)" by simp
    have "n = 1  (drop n (x # y # ys)) = y # ys" by simp
    then show ?thesis using n0 3 walk or by auto
  qed
qed

definition walks :: "'a list set" where
  "walks  {p. is_walk p}"

definition is_open_walk :: "'a list  bool" where
"is_open_walk xs  is_walk xs  hd xs  last xs"

lemma is_open_walk_rev: "is_open_walk xs  is_open_walk (rev xs)"
  unfolding is_open_walk_def using is_walk_rev
  by (metis hd_rev last_rev) 

definition is_closed_walk :: "'a list  bool" where
"is_closed_walk xs  is_walk xs  hd xs = last xs"

lemma is_closed_walk_rev: "is_closed_walk xs  is_closed_walk (rev xs)"
  unfolding is_closed_walk_def using is_walk_rev
  by (metis hd_rev last_rev)

definition is_trail :: "'a list  bool" where
"is_trail xs  is_walk xs  distinct (walk_edges xs)"

lemma is_trail_rev: "is_trail xs  is_trail (rev xs)"
  unfolding is_trail_def using is_walk_rev
  by (metis distinct_rev walk_edges_rev) 

subsection ‹Paths›

text ‹There are two common definitions of a path. The first, given below, excludes the case
where a path is a cycle. Note this also excludes the trivial path $[x]$›
definition is_path :: "'a list  bool" where
"is_path xs  (is_open_walk xs  distinct (xs))"

lemma is_path_rev: "is_path xs  is_path (rev xs)"
  unfolding is_path_def using is_open_walk_rev 
  by (metis distinct_rev)

lemma is_path_walk: "is_path xs  is_walk xs"
  unfolding is_path_def is_open_walk_def by auto

definition paths :: "'a list set" where 
"paths  {p . is_path p}"

lemma paths_ss_walk: "paths  walks"
  unfolding paths_def walks_def is_path_def is_open_walk_def by auto

text ‹ A more generic definition of a path - used when a cycle is considered a path, and 
therefore includes the trivial path $[x]$ ›
definition is_gen_path:: "'a list  bool" where
"is_gen_path p  is_walk p  ((distinct (tl p)  hd p = last p)  distinct p)"

lemma is_path_gen_path: "is_path p  is_gen_path p"
  unfolding is_path_def is_gen_path_def is_open_walk_def by (auto simp add: distinct_tl)

lemma is_gen_path_rev: "is_gen_path p  is_gen_path (rev p)"
  unfolding is_gen_path_def using is_walk_rev distinct_tl_rev
  by (metis distinct_rev hd_rev last_rev)

lemma is_gen_path_distinct: "is_gen_path p  hd p  last p  distinct p"
  unfolding is_gen_path_def by auto

lemma is_gen_path_distinct_tl: 
  assumes "is_gen_path p" and "hd p = last p" 
  shows "distinct (tl p)"
proof (cases "length p > 1")
  case True
  then show ?thesis
    using assms(1) distinct_tl is_gen_path_def by auto 
next
  case False
  then show ?thesis
    using assms(1) distinct_tl is_gen_path_def by auto 
qed

lemma is_gen_path_trivial: "x  V  is_gen_path [x]"
  unfolding is_gen_path_def is_walk_def by simp 

definition gen_paths :: "'a list set" where
"gen_paths  {p . is_gen_path p}"

lemma gen_paths_ss_walks: "gen_paths  walks"
  unfolding gen_paths_def walks_def is_gen_path_def by auto

subsection ‹ Cycles ›
text ‹Note, a cycle must be non trivial (i.e. have an edge), but as we let a loop by a cycle
we broaden the definition in comparison to Noschinski cite"noschinski_2015" for a cycle to be of 
length greater than 1 rather than 3 ›
definition is_cycle :: "'a list  bool" where
"is_cycle xs  is_closed_walk xs  walk_length xs  1  distinct (tl xs)"

lemma is_gen_path_cycle: "is_cycle p  is_gen_path p"
  unfolding is_cycle_def is_gen_path_def is_closed_walk_def by auto

lemma is_cycle_alt_gen_path: "is_cycle xs  is_gen_path xs  walk_length xs  1  hd xs = last xs"
proof (intro iffI)
  show "is_cycle xs  is_gen_path xs  1  walk_length xs  hd xs = last xs"
    using is_gen_path_cycle is_cycle_def is_closed_walk_def
    by auto 
  show "is_gen_path xs  1  walk_length xs  hd xs = last xs  is_cycle xs"
    using distinct_tl is_closed_walk_def is_cycle_def is_gen_path_def by blast
qed

lemma is_cycle_alt: "is_cycle xs  is_walk xs  distinct (tl xs)  walk_length xs  1  hd xs = last xs"
proof (intro iffI)
  show "is_cycle xs  is_walk xs  distinct (tl xs)  1  walk_length xs  hd xs = last xs"
    using is_cycle_alt_gen_path is_cycle_def is_gen_path_def by blast 
  show "is_walk xs  distinct (tl xs)  1  walk_length xs  hd xs = last xs  is_cycle xs"
    by (simp add: is_cycle_alt_gen_path is_gen_path_def)
qed

lemma is_cycle_rev: "is_cycle xs  is_cycle (rev xs)"
proof -
  have len: "1  walk_length xs  1  walk_length (rev xs)"
    by (metis length_rev walk_edges_rev walk_length_def)
  have "hd xs = last xs  distinct (tl xs)  distinct (tl (rev xs))"
    using distinct_tl_rev by blast 
  then show ?thesis using len is_cycle_def
    using is_closed_walk_def is_closed_walk_rev by auto 
qed

lemma cycle_tl_is_path: "is_cycle xs  walk_length xs  3  is_path (tl xs)"
proof (simp add: is_cycle_def is_path_def is_open_walk_def is_closed_walk_def walk_length_conv, 
    elim conjE, intro conjI, simp add: is_walk_tl)
  assume w: "is_walk xs" and eq: "hd xs = last xs" and  "3  length xs - Suc 0" and 
    dis: "distinct (tl xs)"
  then have len: "4  length xs"
    by linarith 
  then have lentl: "3  length (tl xs)" by simp
  then have lentltl: "2  length (tl (tl xs))" by simp
  have "last (tl (tl xs)) = last (tl xs)"
    by (metis One_nat_def Suc_1 3  length xs - Suc 0 diff_is_0_eq' is_walk_def is_walk_tl last_tl 
        lentl not_less_eq_eq numeral_le_one_iff one_le_numeral order.trans semiring_norm(70) w) 
  then have "last (tl xs)  set (tl (tl xs))"
    using  last_in_list_tl_set lentltl by (metis last_in_set list.sel(2))  
  moreover have "hd (tl xs)  set (tl (tl xs))" using dis lentltl
    by (metis distinct.simps(2) hd_Cons_tl list.sel(2) list.size(3) not_numeral_le_zero) 
  ultimately show "hd (tl xs)  last (tl xs)" by fastforce 
qed

lemma is_gen_path_path: 
  assumes "is_gen_path p" and "walk_length p > 0" and "(¬ is_cycle p)"
  shows "is_path p"
proof (simp add: is_gen_path_def is_path_def is_open_walk_def, intro conjI)
  show "is_walk p" using is_gen_path_def assms(1) by simp
  show ne: "hd p  last p"
    using assms(1) assms(2) assms(3) is_cycle_alt_gen_path by auto 
  have "((distinct (tl p)  hd p = last p)  distinct p)" using is_gen_path_def assms(1) by auto
  thus "distinct p" using ne by auto
qed

lemma is_gen_path_options: "is_gen_path p  is_cycle p  is_path p  ( v  V. p = [v])"
proof (intro iffI)
  assume a: "is_gen_path p"
  then have "p  []" unfolding is_gen_path_def is_walk_def by auto
  then have "( v  V . p  [v])  walk_length p > 0" using walk_length_def
    by (metis a is_gen_path_def is_walk_wf_hd length_greater_0_conv list.collapse list.distinct(1) walk_edges.simps(3)) 
  then show "is_cycle p  is_path p  ( v  V. p = [v])"
    using a is_gen_path_path by auto
next
  show "is_cycle p  is_path p  ( v  V. p = [v])  is_gen_path p " 
    using is_gen_path_cycle is_path_gen_path is_gen_path_trivial by auto
qed

definition cycles :: "'a list set" where
  "cycles  {p. is_cycle p}"

lemma cycles_ss_gen_paths: "cycles  gen_paths"
  unfolding cycles_def gen_paths_def using is_gen_path_cycle by auto

lemma gen_paths_ss: "gen_paths  cycles  paths  {[v] | v. v  V}"
  unfolding gen_paths_def cycles_def paths_def using is_gen_path_options by auto

text ‹Walk edges are distinct in a path and cycle ›
lemma distinct_edgesI:
  assumes "distinct p" shows "distinct (walk_edges p)"
proof -
  from assms have "?thesis" "u. u  set p  (v. u  v  {u,v}  set (walk_edges p))"
    by (induct p rule: walk_edges.induct) auto
  then show ?thesis by simp
qed

lemma scycles_distinct_edges:
  assumes "c  cycles" "3  walk_length c" shows "distinct (walk_edges c)"
proof -
  from assms  have c_props: "distinct (tl c)" "4  length c" "hd c = last c"
    by (auto simp add: cycles_def is_cycle_def is_closed_walk_def walk_length_conv)
  then have "{hd c, hd (tl c)}  set (walk_edges (tl c))"
  proof (induct c rule: walk_edges.induct)
    case (3 x y ys)
    then have "hd ys  last ys" by (cases ys) auto
    moreover
    from 3 have "walk_edges (y # ys) = {y, hd ys} # walk_edges ys"
      by (cases ys) auto
    moreover
    { fix xs have "set (walk_edges xs)  Pow (set xs)"
        by (induct xs rule: walk_edges.induct) auto }
    ultimately
    show ?case using 3 by auto
  qed simp_all
  moreover
  from assms have "distinct (walk_edges (tl c))"
    by (intro distinct_edgesI) (simp add: cycles_def is_cycle_def)
  ultimately
  show ?thesis by(cases c, simp_all) 
      (metis distinct.simps(1) distinct.simps(2) list.sel(1) list.sel(3) walk_edges.elims)
qed

end

context fin_ulgraph
begin

lemma finite_paths: "finite paths"
proof -
  have ss: "paths  {xs. set xs  V  length xs  (card (V))}"
  proof (rule, simp, intro conjI)
    show 1: "x. x  paths  set x  V"
      unfolding paths_def is_path_def is_open_walk_def is_walk_def by simp
    fix x assume a: "x  paths"
    then have "distinct x" 
      using paths_def is_path_def by simp_all
    then have eq: "length x = card (set x)"
      by (simp add: distinct_card)
    then show "length x  gorder" using a 1
      by (simp add: card_mono finV) 
  qed
  have "finite {xs. set xs  V  length xs  (card (V))}"
    using finV by (simp add: finite_lists_length_le) 
  thus ?thesis using ss finite_subset by auto
qed

lemma finite_cycles: "finite (cycles)"
proof -
  have "cycles  {xs. set xs  V  length xs  Suc (card (V))}"
  proof (rule, simp)
    fix p assume "p  cycles"
    then have "distinct (tl p)" and "set p  V"
      unfolding cycles_def walks_def is_cycle_def is_closed_walk_def is_walk_def
      by (simp_all) 
    then have "set (tl p)  V"
      by (cases p) auto
    with finV have "card (set (tl p))  card (V)"
      by (rule card_mono)
    then have "length (p)  1 + card (V)"
      using distinct_card[OF distinct (tl p)] by auto
    then show "set p  V  length p  Suc (card (V))"
      by (simp add: set p  V) 
  qed
  moreover
  have "finite {xs. set xs  V  length xs  Suc (card (V))}"
    using finV by (rule finite_lists_length_le)
  ultimately
  show ?thesis by (rule finite_subset)
qed

lemma finite_gen_paths: "finite (gen_paths)"
proof -
  have "finite ({[v] | v . v  V})" using finV by auto
  thus ?thesis  using gen_paths_ss finite_cycles finite_paths finite_subset by auto
qed

end

end