Theory Tree_Graph
section ‹Graphs and Trees›
theory Tree_Graph
  imports Undirected_Graph_Theory.Undirected_Graphs_Root
begin
subsection ‹Miscellaneous›
definition (in ulgraph) loops :: "'a edge set" where
  "loops = {e∈E. is_loop e}"
definition (in ulgraph) sedges :: "'a edge set" where
  "sedges = {e∈E. is_sedge e}"
lemma (in ulgraph) union_loops_sedges: "loops ∪ sedges = E"
  unfolding loops_def sedges_def is_loop_def is_sedge_def using alt_edge_size by blast
lemma (in ulgraph) disjnt_loops_sedges: "disjnt loops sedges"
  unfolding disjnt_def loops_def sedges_def is_loop_def is_sedge_def by auto
lemma (in fin_ulgraph) finite_loops: "finite loops"
  unfolding loops_def using fin_edges by auto
lemma (in fin_ulgraph) finite_sedges: "finite sedges"
  unfolding sedges_def using fin_edges by auto
lemma (in ulgraph) edge_incident_vert: "e ∈ E ⟹ ∃v∈V. vincident v e"
  using edge_size wellformed by (metis empty_not_edge equals0I vincident_def incident_edge_in_wf)
lemma (in ulgraph) Union_incident_edges: "(⋃v∈V. incident_edges v) = E"
  unfolding incident_edges_def using edge_incident_vert by auto
lemma (in ulgraph) induced_edges_mono: "V⇩1 ⊆ V⇩2 ⟹ induced_edges V⇩1 ⊆ induced_edges V⇩2"
  using induced_edges_def by auto
definition (in graph_system) remove_vertex :: "'a ⇒ 'a pregraph" where
  "remove_vertex v = (V - {v}, {e∈E. ¬ vincident v e})"
lemma (in ulgraph) ex_neighbor_degree_not_0:
  assumes degree_non_0: "degree v ≠ 0"
    shows "∃u∈V. vert_adj v u"
proof-
  have "∃e∈E. v ∈ e" using degree_non_0 elem_exists_non_empty_set
    unfolding degree_def incident_sedges_def incident_loops_def vincident_def by auto
  then show ?thesis
    by (metis degree_non_0 in_mono is_isolated_vertex_def is_isolated_vertex_degree0 vert_adj_sym wellformed)
qed
lemma (in ulgraph) ex1_neighbor_degree_1:
  assumes degree_1: "degree v = 1"
  shows "∃!u. vert_adj v u"
proof-
  have "card (incident_loops v) = 0" using degree_1 unfolding degree_def by auto
  then have incident_loops: "incident_loops v = {}" by (simp add: finite_incident_loops)
  then have card_incident_sedges: "card (incident_sedges v) = 1" using degree_1 unfolding degree_def by simp
  obtain u where vert_adj: "vert_adj v u" using degree_1 ex_neighbor_degree_not_0 by force
  then have "u ≠ v" using incident_loops unfolding incident_loops_def vert_adj_def by blast
  then have u_incident: "{v,u} ∈ incident_sedges v" using vert_adj unfolding incident_sedges_def vert_adj_def vincident_def by simp
  then have incident_sedges: "incident_sedges v = {{v,u}}" using card_incident_sedges
    by (simp add: comp_sgraph.card1_incident_imp_vert comp_sgraph.vincident_def)
  have "vert_adj v u' ⟹ u' = u" for u'
  proof-
    assume v_u'_adj: "vert_adj v u'"
    then have "u' ≠ v" using incident_loops unfolding incident_loops_def vert_adj_def by blast
    then have "{v,u'} ∈ incident_sedges v" using v_u'_adj unfolding incident_sedges_def vert_adj_def vincident_def by simp
    then show "u' = u" using incident_sedges by force
  qed
  then show ?thesis using vert_adj by blast
qed
lemma (in ulgraph) degree_1_edge_partition:
  assumes degree_1: "degree v = 1"
  shows "E = {{THE u. vert_adj v u, v}} ∪ {e ∈ E. v ∉ e}"
proof-
  have "card (incident_loops v) = 0" using degree_1 unfolding degree_def by auto
  then have incident_loops: "incident_loops v = {}" by (simp add: finite_incident_loops)
  then have "card (incident_sedges v) = 1" using degree_1 unfolding degree_def by simp
  then have card_incident_edges: "card (incident_edges v) = 1" using incident_loops incident_edges_union by simp
  obtain u where vert_adj: "vert_adj v u" using ex1_neighbor_degree_1 degree_1 by blast
  then have "{v, u} ∈ {e ∈ E. v ∈ e}" unfolding vert_adj_def by blast
  then have edges_incident_v: "{e ∈ E. v ∈ e} = {{v, u}}" using card_incident_edges card_1_singletonE singletonD
    unfolding incident_edges_def vincident_def by metis
  have u: "u = (THE u. vert_adj v u)" using vert_adj ex1_neighbor_degree_1 degree_1
    by (simp add: the1_equality)
  show ?thesis using edges_incident_v u by blast
qed
lemma (in sgraph) vert_adj_not_eq: "vert_adj u v ⟹ u ≠ v"
  unfolding vert_adj_def using edge_vertices_not_equal by blast
subsection ‹Degree›
lemma (in ulgraph) empty_E_degree_0: "E = {} ⟹ degree v = 0"
  using incident_edges_empty degree0_inc_edges_empt_iff unfolding incident_edges_def by simp
lemma (in fin_ulgraph) handshaking: "(∑v∈V. degree v) = 2 * card E"
  using fin_edges fin_ulgraph_axioms
proof (induction E)
  case empty
  then interpret g: fin_ulgraph V "{}" .
  show ?case using g.empty_E_degree_0 by simp
next
  case (insert e E')
  then interpret g': fin_ulgraph V "insert e E'" by blast
  interpret g: fin_ulgraph V E' using g'.wellformed g'.edge_size finV by (unfold_locales, auto)
  show ?case
  proof (cases "is_loop e")
    case True
    then obtain u where e: "e = {u}" using card_1_singletonE is_loop_def by blast
    then have inc_sedges: "⋀v. g'.incident_sedges v = g.incident_sedges v" unfolding g'.incident_sedges_def g.incident_sedges_def by auto
    have "⋀v. v ≠ u ⟹ g'.incident_loops v = g.incident_loops v" unfolding g'.incident_loops_def g.incident_loops_def using e by auto
    then have degree_not_u: "⋀v. v ≠ u ⟹ g'.degree v = g.degree v" using inc_sedges unfolding g'.degree_def g.degree_def by auto
    have "g'.incident_loops u = g.incident_loops u ∪ {e}" unfolding g'.incident_loops_def g.incident_loops_def using e by auto
    then have degree_u: "g'.degree u = g.degree u + 2" using inc_sedges insert(2) g.finite_incident_loops g.incident_loops_def unfolding g'.degree_def g.degree_def by auto
    have "u ∈ V" using e g'.wellformed by blast
    then have "(∑v∈V. g'.degree v) = g'.degree u + (∑v∈V-{u}. g'.degree v)"
      by (simp add: finV sum.remove)
    also have "… = (∑v∈V. g.degree v) + 2" using degree_not_u degree_u sum.remove[OF finV ‹u∈V›, of g.degree] by auto
    also have "… = 2 * card (insert e E')" using insert g.fin_ulgraph_axioms by auto
    finally show ?thesis .
  next
    case False
    obtain u w where e: "e = {u,w}" using g'.obtain_edge_pair_adj by fastforce
    then have card_e: "card e = 2" using False g'.alt_edge_size is_loop_def by auto
    then have "u ≠ w" using card_2_iff using e by fastforce
    have inc_loops: "⋀v. g'.incident_loops v = g.incident_loops v"
      unfolding g'.incident_loops_alt g.incident_loops_alt using False is_loop_def by auto
    have "⋀v. v ≠ u ⟹ v ≠ w ⟹ g'.incident_sedges v = g.incident_sedges v"
      unfolding g'.incident_sedges_def g.incident_sedges_def g.vincident_def using e by auto
    then have degree_not_u_w: "⋀v. v ≠ u ⟹ v ≠ w ⟹ g'.degree v = g.degree v"
      unfolding g'.degree_def g.degree_def using inc_loops by auto
    have "g'.incident_sedges u = g.incident_sedges u ∪ {e}"
      unfolding g'.incident_sedges_def g.incident_sedges_def g.vincident_def using e card_e by auto
    then have degree_u: "g'.degree u = g.degree u + 1"
      using inc_loops insert(2) g.fin_edges g.finite_inc_sedges g.incident_sedges_def
      unfolding g'.degree_def g.degree_def by auto
    have "g'.incident_sedges w = g.incident_sedges w ∪ {e}"
      unfolding g'.incident_sedges_def g.incident_sedges_def g.vincident_def using e card_e by auto
    then have degree_w: "g'.degree w = g.degree w + 1"
      using inc_loops insert(2) g.fin_edges g.finite_inc_sedges g.incident_sedges_def
      unfolding g'.degree_def g.degree_def by auto
    have inV: "u ∈ V" "w ∈ V-{u}" using e g'.wellformed ‹u≠w› by auto
    then have "(∑v∈V. g'.degree v) = g'.degree u + g'.degree w + (∑v∈V-{u}-{w}. g'.degree v)"
      using sum.remove finV by (metis add.assoc finite_Diff)
    also have "… = g.degree u + g.degree w + (∑v∈V-{u}-{w}. g.degree v) + 2"
      using degree_not_u_w degree_u degree_w by simp
    also have "… = (∑v∈V. g.degree v) + 2" using sum.remove finV inV by (metis add.assoc finite_Diff)
    also have "… = 2 * card (insert e E')" using insert g.fin_ulgraph_axioms by auto
    finally show ?thesis .
  qed
qed
lemma (in fin_ulgraph) degree_remove_adj_ne_vert:
  assumes "u ≠ v"
    and vert_adj: "vert_adj u v"
    and remove_vertex: "remove_vertex u = (V',E')"
  shows "ulgraph.degree E' v = degree v - 1"
proof-
  interpret G': fin_ulgraph V' E' using remove_vertex wellformed edge_size finV unfolding remove_vertex_def vincident_def
    by (unfold_locales, auto)
  have E': "E' = {e ∈ E. u ∉ e}" using remove_vertex unfolding remove_vertex_def vincident_def by simp
  have incident_loops': "G'.incident_loops v = incident_loops v" unfolding incident_loops_def
    using ‹u≠v› E' G'.incident_loops_def by auto
  have uv_incident: "{u,v} ∈ incident_sedges v" using vert_adj ‹u≠v› unfolding vert_adj_def incident_sedges_def vincident_def by simp
  have uv_incident': "{u, v} ∉ G'.incident_sedges v" unfolding G'.incident_sedges_def vincident_def using E' by blast
  have "e ∈ E ⟹ u ∈ e ⟹ v ∈ e ⟹ card e = 2 ⟹ e = {u,v}" for e
    using ‹u≠v› obtain_edge_pair_adj by blast
  then have "{e ∈ E. u ∈ e ∧ v ∈ e ∧ card e = 2} = {{u,v}}" using uv_incident unfolding incident_sedges_def by blast
  then have "incident_sedges v = G'.incident_sedges v ∪ {{u,v}}" unfolding G'.incident_sedges_def incident_sedges_def vincident_def using E' by blast
  then show ?thesis unfolding G'.degree_def degree_def using incident_loops' uv_incident' G'.finite_inc_sedges G'.fin_edges by auto
qed
lemma (in ulgraph) degree_remove_non_adj_vert:
  assumes "u ≠ v"
    and vert_non_adj: "¬ vert_adj u v"
    and remove_vertex: "remove_vertex u = (V', E')"
  shows "ulgraph.degree E' v = degree v"
proof-
  interpret G': ulgraph V' E' using remove_vertex wellformed edge_size unfolding remove_vertex_def vincident_def
    by (unfold_locales, auto)
  have E': "E' = {e ∈ E. u ∉ e}" using remove_vertex unfolding remove_vertex_def vincident_def by simp
  have incident_loops': "G'.incident_loops v = incident_loops v" unfolding incident_loops_def
    using ‹u≠v› E' G'.incident_loops_def by auto
  have "G'.incident_sedges v = incident_sedges v" unfolding G'.incident_sedges_def incident_sedges_def vincident_def
    using E' ‹u≠v› vincident_def vert_adj_edge_iff2 vert_non_adj by auto
  then show ?thesis using incident_loops' unfolding G'.degree_def degree_def by simp
qed
subsection ‹Walks›
lemma (in ulgraph) walk_edges_induced_edges: "is_walk p ⟹ set (walk_edges p) ⊆ induced_edges (set p)"
  unfolding induced_edges_def is_walk_def by (induction p rule: walk_edges.induct) auto
lemma (in ulgraph) walk_edges_in_verts: "e ∈ set (walk_edges xs) ⟹ e ⊆ set xs"
  by (induction xs rule: walk_edges.induct) auto
lemma (in ulgraph) is_walk_prefix: "is_walk (xs@ys) ⟹ xs ≠ [] ⟹ is_walk xs"
  unfolding is_walk_def using walk_edges_append_ss2 by fastforce
lemma (in ulgraph) split_walk_edge: "{x,y} ∈ set (walk_edges p) ⟹
  ∃xs ys. p = xs @ x # y # ys ∨ p = xs @ y # x # ys"
  by (induction p rule: walk_edges.induct) (auto, metis append_Nil doubleton_eq_iff, (metis append_Cons)+)
subsection ‹Paths›
lemma (in ulgraph) is_gen_path_wf: "is_gen_path p ⟹ set p ⊆ V"
  unfolding is_gen_path_def using is_walk_wf by auto
lemma (in ulgraph) path_wf: "is_path p ⟹ set p ⊆ V"
  by (simp add: is_path_walk is_walk_wf)
lemma (in fin_ulgraph) length_gen_path_card_V: "is_gen_path p ⟹ walk_length p ≤ card V"
  by (metis card_mono distinct_card distinct_tl finV is_gen_path_def is_walk_def length_tl
      list.exhaust_sel order_trans set_subset_Cons walk_length_conv)
lemma (in fin_ulgraph) length_path_card_V: "is_path p ⟹ length p ≤ card V"
  by (metis path_wf card_mono distinct_card finV is_path_def)
lemma (in ulgraph) is_gen_path_prefix: "is_gen_path (xs@ys) ⟹ xs ≠ [] ⟹ is_gen_path (xs)"
  unfolding is_gen_path_def using is_walk_prefix
  by (auto, metis Int_iff distinct.simps(2) emptyE last_appendL last_appendR last_in_set list.collapse)
lemma (in ulgraph) connecting_path_append: "connecting_path u w (xs@ys) ⟹ xs ≠ [] ⟹ connecting_path u (last xs) xs"
  unfolding connecting_path_def using is_gen_path_prefix by auto
lemma (in ulgraph) connecting_path_tl: "connecting_path u v (u # w # xs) ⟹ connecting_path w v (w # xs)"
  unfolding connecting_path_def is_gen_path_def using is_walk_drop_hd distinct_tl by auto
lemma (in fin_ulgraph) obtain_longest_path:
  assumes "e ∈ E"
    and sedge: "is_sedge e"
  obtains p where "is_path p" "∀s. is_path s ⟶ length s ≤ length p"
proof-
  let ?longest_path = "ARG_MAX length p. is_path p"
  obtain u v where e: "u ≠ v" "e = {u,v}" using sedge card_2_iff unfolding is_sedge_def by metis
  then have inV: "u ∈ V" "v ∈ V" using ‹e∈E› wellformed by auto
  then have path_ex: "is_path [u,v]" using e ‹e∈E› unfolding is_path_def is_open_walk_def is_walk_def by simp
  obtain p where p_is_path: "is_path p" and p_longest_path: "∀s. is_path s ⟶ length s ≤ length p"
    using path_ex length_path_card_V ex_has_greatest_nat[of is_path "[u,v]" length gorder] by force
  then show ?thesis ..
qed
subsection ‹Cycles›
context ulgraph
begin
definition is_cycle2 :: "'a list ⇒ bool" where
  "is_cycle2 xs ⟷ is_cycle xs ∧ distinct (walk_edges xs)"
lemma loop_is_cycle2: "{v} ∈ E ⟹ is_cycle2 [v, v]"
  unfolding is_cycle2_def is_cycle_alt is_walk_def using wellformed walk_length_conv by auto
end
lemma (in sgraph) cycle2_min_length:
  assumes cycle: "is_cycle2 c"
  shows "walk_length c ≥ 3"
proof-
  consider "c = []" | "∃v1. c = [v1]" | "∃v1 v2. c = [v1, v2]" | "∃v1 v2 v3. c = [v1, v2, v3]" | "∃v1 v2 v3 v4 vs. c = v1#v2#v3#v4#vs"
    by (metis list.exhaust_sel)
  then show ?thesis using cycle walk_length_conv singleton_not_edge unfolding is_cycle2_def is_cycle_alt is_walk_def by (cases, auto)
qed
lemma (in fin_ulgraph) length_cycle_card_V: "is_cycle c ⟹ walk_length c ≤ Suc (card V)"
  using length_gen_path_card_V unfolding is_gen_path_def is_cycle_alt by fastforce
lemma (in ulgraph) is_cycle_connecting_path: "is_cycle (u#v#xs) ⟹ connecting_path v u (v#xs)"
  unfolding is_cycle_def connecting_path_def is_closed_walk_def is_gen_path_def using is_walk_drop_hd by auto
lemma (in ulgraph) cycle_edges_notin_tl: "is_cycle2 (u#v#xs) ⟹ {u,v} ∉ set (walk_edges (v#xs))"
  unfolding is_cycle2_def by simp
subsection ‹Subgraphs›
locale ulsubgraph = subgraph V⇩H E⇩H V⇩G E⇩G +
  G: ulgraph V⇩G E⇩G for V⇩H E⇩H V⇩G E⇩G
begin
interpretation H: ulgraph V⇩H E⇩H
  using is_subgraph_ulgraph G.ulgraph_axioms by auto
lemma is_walk: "H.is_walk xs ⟹ G.is_walk xs"
  unfolding H.is_walk_def G.is_walk_def using verts_ss edges_ss by blast
lemma is_closed_walk: "H.is_closed_walk xs ⟹ G.is_closed_walk xs"
  unfolding H.is_closed_walk_def G.is_closed_walk_def using is_walk by blast
lemma is_gen_path: "H.is_gen_path p ⟹ G.is_gen_path p"
  unfolding H.is_gen_path_def G.is_gen_path_def using is_walk by blast
lemma connecting_path: "H.connecting_path u v p ⟹ G.connecting_path u v p"
  unfolding H.connecting_path_def G.connecting_path_def using is_gen_path by blast
lemma is_cycle: "H.is_cycle c ⟹ G.is_cycle c"
  unfolding H.is_cycle_def G.is_cycle_def using is_closed_walk by blast
lemma is_cycle2: "H.is_cycle2 c ⟹ G.is_cycle2 c"
  unfolding H.is_cycle2_def G.is_cycle2_def using is_cycle by blast
lemma vert_connected: "H.vert_connected u v ⟹ G.vert_connected u v"
  unfolding H.vert_connected_def G.vert_connected_def using connecting_path by blast
lemma is_connected_set: "H.is_connected_set V' ⟹ G.is_connected_set V'"
  unfolding H.is_connected_set_def G.is_connected_set_def using vert_connected by blast
end
lemma (in graph_system) subgraph_remove_vertex: "remove_vertex v = (V', E') ⟹ subgraph V' E' V E"
  using wellformed unfolding remove_vertex_def vincident_def by (unfold_locales, auto)
subsection ‹Connectivity›
lemma (in ulgraph) connecting_path_connected_set:
  assumes conn_path: "connecting_path u v p"
  shows "is_connected_set (set p)"
proof-
  have "∀w∈set p. vert_connected u w"
  proof
    fix w assume "w ∈ set p"
    then obtain xs ys where "p = xs@[w]@ys" using split_list by fastforce
    then have "connecting_path u w (xs@[w])" using conn_path unfolding connecting_path_def using is_gen_path_prefix by (auto simp: hd_append)
    then show "vert_connected u w" unfolding vert_connected_def by blast
  qed
  then show ?thesis using vert_connected_rev vert_connected_trans unfolding is_connected_set_def by blast
qed
lemma (in ulgraph) vert_connected_neighbors:
  assumes "{v,u} ∈ E"
  shows "vert_connected v u"
proof-
  have "connecting_path v u [v,u]" unfolding connecting_path_def is_gen_path_def is_walk_def using assms wellformed by auto
  then show ?thesis unfolding vert_connected_def by auto
qed
lemma (in ulgraph) connected_empty_E:
  assumes empty: "E = {}"
    and connected: "vert_connected u v"
  shows "u = v"
proof (rule ccontr)
  assume "u ≠ v"
  then obtain p where conn_path: "connecting_path u v p" using connected unfolding vert_connected_def by blast
  then obtain e where "e ∈ set (walk_edges p)" using ‹u≠v› connecting_path_length_bound unfolding walk_length_def by fastforce
  then have "e ∈ E" using conn_path unfolding connecting_path_def is_gen_path_def is_walk_def by blast
  then show False using empty by blast
qed
lemma (in fin_ulgraph) degree_0_not_connected:
  assumes degree_0: "degree v = 0"
    and "u ≠ v"
  shows "¬ vert_connected v u"
proof
  assume connected: "vert_connected v u"
  then obtain p where conn_path: "connecting_path v u p" unfolding vert_connected_def by blast
  then have "walk_length p ≥ 1" using ‹u≠v› connecting_path_length_bound by metis
  then have "length p ≥ 2" using walk_length_conv by simp
  then obtain w p' where "p = v#w#p'" using walk_length_conv conn_path unfolding connecting_path_def
    by (metis assms(2) is_gen_path_def is_walk_not_empty2 last_ConsL list.collapse)
  then have inE: "{v,w} ∈ E" using conn_path unfolding connecting_path_def is_gen_path_def is_walk_def by simp
  then have "{v,w} ∈ incident_edges v" unfolding incident_edges_def vincident_def by simp
  then show False using degree0_inc_edges_empt_iff fin_edges degree_0 by blast
qed
lemma (in fin_connected_ulgraph) degree_not_0:
  assumes "card V ≥ 2"
    and inV: "v ∈ V"
  shows "degree v ≠ 0"
proof-
  obtain u where "u ∈ V" and "u ≠ v" using assms
    by (metis card_eq_0_iff card_le_Suc0_iff_eq less_eq_Suc_le nat_less_le not_less_eq_eq numeral_2_eq_2)
  then show ?thesis using degree_0_not_connected inV vertices_connected by blast
qed
lemma (in connected_ulgraph) V_E_empty: "E = {} ⟹ ∃v. V = {v}"
  using connected_empty_E connected not_empty unfolding is_connected_set_def
  by (metis ex_in_conv insert_iff mk_disjoint_insert)
lemma (in connected_ulgraph) vert_connected_remove_edge:
  assumes e: "{u,v} ∈ E"
  shows "∀w∈V. ulgraph.vert_connected V (E - {{u,v}}) w u ∨ ulgraph.vert_connected V (E - {{u,v}}) w v"
proof
  fix w assume "w∈V"
  interpret g': ulgraph V "E - {{u,v}}" using wellformed edge_size by (unfold_locales, auto)
  have inV: "u ∈ V" "v ∈ V" using e wellformed by auto
  obtain p where conn_path: "connecting_path w v p" using connected inV ‹w∈V› unfolding is_connected_set_def vert_connected_def by blast
  then show "g'.vert_connected w u ∨ g'.vert_connected w v"
  proof (cases "{u,v} ∈ set (walk_edges p)")
    case True
    assume walk_edge: "{u,v} ∈ set (walk_edges p)"
    then show ?thesis
    proof (cases "w = v")
      case True
      then show ?thesis using inV g'.vert_connected_id by blast
    next
      case False
      then have distinct: "distinct p" using conn_path by (simp add: connecting_path_def is_gen_path_distinct)
      have "u ∈ set p" using walk_edge walk_edges_in_verts by blast
      obtain xs ys where p_split: "p = xs @ u # v # ys ∨ p = xs @ v # u # ys" using split_walk_edge[OF walk_edge] by blast
      have v_notin_ys: "v ∉ set ys" using distinct p_split by auto
      have "last p = v" using conn_path unfolding connecting_path_def by simp
      then have p: "p = (xs@[u]) @ [v]" using v_notin_ys p_split last_in_set last_appendR
        by (metis append.assoc append_Cons last.simps list.discI self_append_conv2)
      then have conn_path_u: "connecting_path w u (xs@[u])" using connecting_path_append conn_path by fastforce
      have "v ∉ set (xs@[u])" using p distinct by auto
      then have "{u,v} ∉ set (walk_edges (xs@[u]))" using walk_edges_in_verts by blast
      then have "g'.connecting_path w u (xs@[u])" using conn_path_u
        unfolding g'.connecting_path_def connecting_path_def g'.is_gen_path_def is_gen_path_def g'.is_walk_def is_walk_def by blast
      then show ?thesis unfolding g'.vert_connected_def by blast
    qed
  next
    case False
    then have "g'.connecting_path w v p" using conn_path
      unfolding g'.connecting_path_def connecting_path_def g'.is_gen_path_def is_gen_path_def g'.is_walk_def is_walk_def by blast
    then show ?thesis unfolding g'.vert_connected_def by blast
  qed
qed
lemma (in ulgraph) vert_connected_remove_cycle_edge:
  assumes cycle: "is_cycle2 (u#v#xs)"
    shows "ulgraph.vert_connected V (E - {{u,v}}) u v"
proof-
  interpret g': ulgraph V "E - {{u,v}}" using wellformed edge_size by (unfold_locales, auto)
  have conn_path: "connecting_path v u (v#xs)" using cycle is_cycle_connecting_path unfolding is_cycle2_def by blast
  have "{u,v} ∉ set (walk_edges (v#xs))" using cycle unfolding is_cycle2_def by simp
  then have "g'.connecting_path v u (v#xs)" using conn_path
    unfolding g'.connecting_path_def connecting_path_def g'.is_gen_path_def is_gen_path_def g'.is_walk_def is_walk_def by blast
  then show ?thesis using g'.vert_connected_rev unfolding g'.vert_connected_def by blast
qed
lemma (in connected_ulgraph) connected_remove_cycle_edges:
  assumes cycle: "is_cycle2 (u#v#xs)"
  shows "connected_ulgraph V (E - {{u,v}})"
proof-
  interpret g': ulgraph V "E - {{u,v}}" using wellformed edge_size by (unfold_locales, auto)
  have "g'.vert_connected x y" if inV: "x ∈ V" "y ∈ V" for x y
  proof-
    have e: "{u,v} ∈ E" using cycle unfolding is_cycle2_def is_cycle_alt is_walk_def by auto
    show ?thesis using vert_connected_remove_cycle_edge[OF cycle] vert_connected_remove_edge[OF e] g'.vert_connected_trans g'.vert_connected_rev inV by metis
  qed
  then show ?thesis using not_empty by (unfold_locales, auto simp: g'.is_connected_set_def)
qed
lemma (in connected_ulgraph) connected_remove_leaf:
  assumes degree: "degree l = 1"
    and remove_vertex: "remove_vertex l = (V', E')"
  shows "ulgraph.is_connected_set V' E' V'"
proof-
  interpret g': ulgraph V' E' using remove_vertex wellformed edge_size
    unfolding remove_vertex_def vincident_def by (unfold_locales, auto)
  have V': "V' = V - {l}" using remove_vertex unfolding remove_vertex_def by simp
  have E': "E' = {e∈E. l ∉ e}" using remove_vertex unfolding remove_vertex_def vincident_def by simp
  have "u ∈ V' ⟹ v ∈ V' ⟹ g'.vert_connected u v" for u v
  proof-
    assume inV': "u ∈ V'" "v ∈ V'"
    then have inV: "u ∈ V" "v ∈ V" using remove_vertex unfolding remove_vertex_def by auto
    then obtain p where conn_path: "connecting_path u v p" using vertices_connected_path by blast
    show ?thesis
    proof (cases "u = v")
      case True
      then show ?thesis using g'.vert_connected_id inV' by simp
    next
      case False
      then have distinct: "distinct p" using conn_path unfolding connecting_path_def is_gen_path_def by blast
      have l_notin_p: "l ∉ set p"
      proof
        assume l_in_p: "l ∈ set p"
        then obtain xs ys where p: "p = xs @ l # ys" by (meson split_list)
        have "l ≠ u" "l ≠ v" using inV' remove_vertex unfolding remove_vertex_def by auto
        then have "xs ≠ []" using p conn_path unfolding connecting_path_def by fastforce
        then obtain x where last_xs: "last xs = x" by simp
        then have "x ≠ l" using distinct p ‹xs≠[]› by auto
        have "{x,l} ∈ set (walk_edges p)" using walk_edges_append_union ‹xs≠[]› unfolding p
          by (simp add: walk_edges_append_union last_xs)
        then have xl_incident: "{x,l} ∈ incident_sedges l" using conn_path ‹x≠l›
          unfolding connecting_path_def is_gen_path_def is_walk_def incident_sedges_def vincident_def by auto
        have "ys ≠ []" using ‹l≠v› p conn_path unfolding connecting_path_def by fastforce
        then obtain y ys' where ys: "ys = y # ys'" by (meson list.exhaust)
        then have "y ≠ l" using distinct p by auto
        then have "{y,l} ∈ set (walk_edges p)" using p ys conn_path walk_edges_append_ss1 by fastforce
        then have yl_incident: "{y,l} ∈ incident_sedges l" using conn_path ‹y≠l›
          unfolding connecting_path_def is_gen_path_def is_walk_def incident_sedges_def vincident_def by auto
        have card_loops: "card (incident_loops l) = 0" using degree unfolding degree_def by auto
        have "x ≠ y" using distinct last_xs ‹xs≠[]› unfolding p ys by fastforce
        then have "{x,l} ≠ {y,l}" by (metis doubleton_eq_iff)
        then have "card (incident_sedges l) ≠ 1" using xl_incident yl_incident
          by (metis card_1_singletonE singletonD)
        then have "degree l ≠ 1" using card_loops unfolding degree_def by simp
        then show False using degree ..
      qed
      then have "set (walk_edges p) ⊆ E'" using walk_edges_in_verts conn_path E' unfolding connecting_path_def is_gen_path_def is_walk_def by blast
      then have "g'.connecting_path u v p" using conn_path V' l_notin_p
        unfolding g'.connecting_path_def connecting_path_def g'.is_gen_path_def is_gen_path_def g'.is_walk_def is_walk_def by blast
      then show ?thesis unfolding g'.vert_connected_def by blast
    qed
  qed
  then show ?thesis unfolding g'.is_connected_set_def by blast
qed
lemma (in connected_sgraph) connected_two_graph_edges:
  assumes "u ≠ v"
    and V: "V = {u,v}"
  shows "E = {{u,v}}"
proof-
  obtain p where conn_path: "connecting_path u v p" using V vertices_connected_path by blast
  then obtain p' where p: "p = u # p' @ [v]" using ‹u≠v› unfolding connecting_path_def is_gen_path_def 
    by (metis append_Nil is_walk_not_empty2 list.exhaust_sel list.sel(1) snoc_eq_iff_butlast tl_append2)
  have "distinct p" using conn_path ‹u≠v› unfolding connecting_path_def is_gen_path_def by auto
  then have "p' = []" using V conn_path is_gen_path_wf append_is_Nil_conv last_in_set self_append_conv2
    unfolding connecting_path_def p by fastforce
  then have edge_in_E: "{u,v} ∈ E" using ‹u≠v› conn_path
    unfolding p connecting_path_def is_gen_path_def is_walk_def by simp
  have "E ⊆ {{}, {u}, {v}, {u,v}}" using wellformed V by blast
  then show ?thesis using two_edges edge_in_E by fastforce
qed
subsection "Connected components"
context ulgraph
begin
abbreviation "vert_connected_rel ≡ {(u,v). vert_connected u v}"
definition connected_components :: "'a set set" where
  "connected_components = V // vert_connected_rel"
definition connected_component_of :: "'a ⇒ 'a set" where
  "connected_component_of v = vert_connected_rel `` {v}"
lemma vert_connected_rel_on_V: "vert_connected_rel ⊆ V × V"
  using vert_connected_wf by auto
lemma vert_connected_rel_refl: "refl_on V vert_connected_rel"
  unfolding refl_on_def using vert_connected_rel_on_V vert_connected_id by simp
lemma vert_connected_rel_sym: "sym vert_connected_rel"
  unfolding sym_def using vert_connected_rev by simp
lemma vert_connected_rel_trans: "trans vert_connected_rel"
  unfolding trans_def using vert_connected_trans by blast
lemma equiv_vert_connected: "equiv V vert_connected_rel"
  unfolding equiv_def using vert_connected_rel_refl vert_connected_rel_sym vert_connected_rel_trans by blast
lemma connected_component_non_empty: "V' ∈ connected_components ⟹ V' ≠ {}"
  unfolding connected_components_def using equiv_vert_connected in_quotient_imp_non_empty by auto
lemma connected_component_connected: "V' ∈ connected_components ⟹ is_connected_set V'"
  unfolding connected_components_def is_connected_set_def using quotient_eq_iff[OF equiv_vert_connected, of V' V'] by simp
lemma connected_component_wf: "V' ∈ connected_components ⟹ V' ⊆ V"
  by (simp add: connected_component_connected is_connected_set_wf)
lemma connected_component_of_self: "v ∈ V ⟹ v ∈ connected_component_of v"
  unfolding connected_component_of_def using vert_connected_id by blast
lemma conn_comp_of_conn_comps: "v ∈ V ⟹ connected_component_of v ∈ connected_components"
  unfolding connected_components_def quotient_def connected_component_of_def by blast
lemma Un_connected_components: "connected_components = connected_component_of ` V"
  unfolding connected_components_def connected_component_of_def quotient_def by blast
lemma connected_component_subgraph: "V' ∈ connected_components ⟹ subgraph V' (induced_edges V') V E"
  using induced_is_subgraph connected_component_wf by simp
lemma connected_components_connected2:
  assumes conn_comp: "V' ∈ connected_components"
  shows "ulgraph.is_connected_set V' (induced_edges V') V'"
proof-
  interpret subg: subgraph V' "induced_edges V'" V E using connected_component_subgraph conn_comp by simp
  interpret g': ulgraph V' "induced_edges V'" using subg.is_subgraph_ulgraph ulgraph_axioms by simp
  have "⋀u v. u ∈ V' ⟹ v ∈ V' ⟹ g'.vert_connected u v"
  proof-
    fix u v assume "u ∈ V'" "v ∈ V'"
    then obtain p where conn_path: "connecting_path u v p" using connected_component_connected conn_comp unfolding is_connected_set_def vert_connected_def by blast
    then have u_in_p: "u ∈ set p" unfolding connecting_path_def is_gen_path_def is_walk_def by force
    then have set_p: "set p ⊆ V'" using connecting_path_connected_set[OF conn_path]
        in_quotient_imp_closed[OF equiv_vert_connected] conn_comp ‹u ∈ V'›
      unfolding is_connected_set_def connected_components_def by blast
    then have "set (g'.walk_edges p) ⊆ induced_edges V'"
      using walk_edges_induced_edges induced_edges_mono conn_path unfolding connecting_path_def is_gen_path_def by blast
    then have "g'.connecting_path u v p"
      using set_p conn_path
      unfolding g'.connecting_path_def g'.connecting_path_def g'.is_gen_path_def g'.is_walk_def
      unfolding connecting_path_def connecting_path_def is_gen_path_def is_walk_def by auto
    then show "g'.vert_connected u v" unfolding g'.vert_connected_def by blast
  qed
  then show ?thesis unfolding g'.is_connected_set_def by blast
qed
lemma vert_connected_connected_component: "C ∈ connected_components ⟹ u ∈ C ⟹ vert_connected u v ⟹ v ∈ C"
  unfolding connected_components_def using equiv_vert_connected in_quotient_imp_closed by fastforce
lemma connected_components_connected_ulgraphs:
  assumes conn_comp: "V' ∈ connected_components"
  shows "connected_ulgraph V' (induced_edges V')"
proof-
  interpret subg: subgraph V' "induced_edges V'" V E using connected_component_subgraph conn_comp by simp
  interpret g': ulgraph V' "induced_edges V'" using subg.is_subgraph_ulgraph ulgraph_axioms by simp
  show ?thesis using conn_comp connected_component_non_empty connected_components_connected2 by (unfold_locales, auto)
qed
lemma connected_components_partition_on_V: "partition_on V connected_components"
  using partition_on_quotient equiv_vert_connected unfolding connected_components_def by blast
lemma Union_connected_components: "⋃connected_components = V"
  using connected_components_partition_on_V unfolding partition_on_def by blast
lemma disjoint_connected_components: "disjoint connected_components"
  using connected_components_partition_on_V unfolding partition_on_def by blast
lemma Union_induced_edges_connected_components: "⋃(induced_edges ` connected_components) = E"
proof-
  have "∃C∈connected_components. e ∈ induced_edges C" if "e ∈ E" for e
  proof-
    obtain u v where e: "e = {u,v}" by (meson ‹e ∈ E› obtain_edge_pair_adj)
    then have "vert_connected u v" using that vert_connected_neighbors by blast
    then have "v ∈ connected_component_of u" unfolding connected_component_of_def by simp
    then have "e ∈ induced_edges (connected_component_of u)" using connected_component_of_self wellformed ‹e∈E› unfolding e induced_edges_def by auto
    then show ?thesis using conn_comp_of_conn_comps e wellformed ‹e∈E› by auto
  qed 
  then show ?thesis using connected_component_wf induced_edges_ss by blast
qed
lemma connected_components_empty_E:
  assumes empty: "E = {}"
  shows "connected_components = {{v} | v. v∈V}"
proof-
  have "∀v∈V. vert_connected_rel``{v} = {v}" using vert_connected_id connected_empty_E empty by auto
  then show ?thesis unfolding connected_components_def quotient_def by auto
qed
lemma connected_iff_connected_components:
  assumes non_empty: "V ≠ {}"
    shows "is_connected_set V ⟷ connected_components = {V}"
proof
  assume "is_connected_set V"
  then have "∀v∈V. connected_component_of v = V" unfolding connected_component_of_def is_connected_set_def using vert_connected_wf by blast
  then show "connected_components = {V}" unfolding quotient_def connected_component_of_def connected_components_def using non_empty by auto
next
  show "connected_components = {V} ⟹ is_connected_set V"
    using connected_component_connected unfolding connected_components_def is_connected_set_def by auto
qed
end
lemma (in connected_ulgraph) connected_components[simp]: "connected_components = {V}"
  using connected connected_iff_connected_components not_empty by simp
lemma (in fin_ulgraph) finite_connected_components: "finite connected_components"
  unfolding connected_components_def using finV vert_connected_rel_on_V finite_quotient by blast
lemma (in fin_ulgraph) finite_connected_component: "C ∈ connected_components ⟹ finite C"
  using connected_component_wf finV finite_subset by blast
lemma (in connected_ulgraph) connected_components_remove_edges:
  assumes edge: "{u,v} ∈ E"
  shows "ulgraph.connected_components V (E - {{u,v}}) =
    {ulgraph.connected_component_of V (E - {{u,v}}) u, ulgraph.connected_component_of V (E - {{u,v}}) v}"
proof-
  interpret g': ulgraph V "E - {{u,v}}" using wellformed edge_size by (unfold_locales, auto)
  have inV: "u ∈ V" "v ∈ V" using edge wellformed by auto
  have "∀w∈V. g'.connected_component_of w = g'.connected_component_of u ∨ g'.connected_component_of w = g'.connected_component_of v"
    using vert_connected_remove_edge[OF edge] g'.equiv_vert_connected equiv_class_eq unfolding g'.connected_component_of_def by fast
  then show ?thesis unfolding g'.connected_components_def quotient_def g'.connected_component_of_def using inV by auto
qed
lemma (in ulgraph) connected_set_connected_component:
  assumes conn_set: "is_connected_set C"
    and non_empty: "C ≠ {}"
    and "⋀u v. {u,v} ∈ E ⟹ u ∈ C ⟹ v ∈ C"
  shows "C ∈ connected_components"
proof-
  have walk_subset_C: "is_walk xs ⟹  hd xs ∈ C ⟹ set xs ⊆ C" for xs
  proof (induction xs rule: rev_induct)
    case Nil
    then show ?case by auto
  next
    case (snoc x xs)
    then show ?case
    proof (cases xs rule: rev_exhaust)
      case Nil
      then show ?thesis using snoc by auto
    next
      fix ys y assume xs: "xs = ys @ [y]"
      then have "is_walk xs" using is_walk_prefix snoc(2) by blast
      then have set_xs_C: "set xs ⊆ C" using snoc xs is_walk_not_empty2 hd_append2 by metis
      have yx_E: "{y,x} ∈ E" using snoc(2) walk_edges_app unfolding xs is_walk_def by simp
      have "x ∈ C" using assms(3)[OF yx_E] set_xs_C unfolding xs by simp
      then show ?thesis using set_xs_C by simp
    qed
  qed
  obtain u where "u ∈ C" using non_empty by blast
  then have "u ∈ V" using conn_set is_connected_set_wf by blast
  have "v ∈ C" if vert_connected: "vert_connected u v" for v
  proof-
    obtain p where "connecting_path u v p" using vert_connected unfolding vert_connected_def by blast
    then show ?thesis using walk_subset_C[of p] ‹u∈C› is_walk_def last_in_set unfolding connecting_path_def is_gen_path_def by auto
  qed
  then have "connected_component_of u = C" using assms ‹u∈C› unfolding connected_component_of_def is_connected_set_def by auto
  then show ?thesis using conn_comp_of_conn_comps ‹u∈V› by blast
qed
lemma (in ulgraph) subset_conn_comps_if_Union:
  assumes A_subset_conn_comps: "A ⊆ connected_components"
    and Un_A: "⋃A = V"
  shows "A = connected_components"
proof (rule ccontr)
  assume "A ≠ connected_components"
  then obtain C where C_conn_comp: "C ∈ connected_components " "C ∉ A" using A_subset_conn_comps by blast
  then obtain v where "v ∈ C" using connected_component_non_empty by blast
  then have "v ∉ V" using A_subset_conn_comps Un_A connected_components_partition_on_V C_conn_comp
    using partition_onD4 by fastforce
  then show False using C_conn_comp connected_component_wf ‹v∈C› by auto
qed
lemma (in connected_ulgraph) exists_adj_vert_removed:
  assumes "v ∈ V"
    and remove_vertex: "remove_vertex v = (V',E')"
    and conn_component: "C ∈ ulgraph.connected_components V' E'"
  shows "∃u∈C. vert_adj v u"
proof-
  have V': "V' = V - {v}" and E': "E' = {e∈E. v ∉ e}" using remove_vertex unfolding remove_vertex_def vincident_def by auto
  interpret subg: subgraph "V - {v}" "{e∈E. v ∉ e}" V E using subgraph_remove_vertex remove_vertex V' E' by metis
  interpret g': ulgraph "V - {v}" "{e∈E. v ∉ e}" using subg.is_subgraph_ulgraph ulgraph_axioms by blast
  obtain c where "c ∈ C" using g'.connected_component_non_empty conn_component V' E' by blast
  then have "c ∈ V'" using g'.connected_component_wf conn_component V' E' by blast
  then have "c ∈ V" using subg.verts_ss V' by blast
  then obtain p where conn_path: "connecting_path v c p" using ‹v∈V› vertices_connected_path by blast  
  have "v ≠ c" using ‹c∈V'› remove_vertex unfolding remove_vertex_def by blast
  then obtain u p' where p: "p = v # u # p'" using conn_path
    by (metis connecting_path_def is_gen_path_def is_walk_def last.simps list.exhaust_sel)
  then have conn_path_uc: "connecting_path u c (u#p')" using conn_path connecting_path_tl unfolding p by blast
  have v_notin_p': "v ∉ set (u#p')" using conn_path ‹v≠c› unfolding p connecting_path_def is_gen_path_def by auto
  then have "g'.connecting_path u c (u#p')" using conn_path_uc v_notin_p' walk_edges_in_verts
    unfolding g'.connecting_path_def connecting_path_def g'.is_gen_path_def is_gen_path_def g'.is_walk_def is_walk_def
    by blast 
  then have "g'.vert_connected u c" unfolding g'.vert_connected_def by blast
  then have "u ∈ C" using ‹c∈C› conn_component g'.vert_connected_connected_component g'.vert_connected_rev unfolding V' E' by blast
  have "vert_adj v u" using conn_path unfolding p connecting_path_def is_gen_path_def is_walk_def vert_adj_def by auto
  then show ?thesis using ‹u∈C› by blast
qed
subsection ‹Trees›
locale tree = fin_connected_ulgraph +
  assumes no_cycles: "¬ is_cycle2 c"
begin
sublocale fin_connected_sgraph
  using alt_edge_size no_cycles loop_is_cycle2 card_1_singletonE connected
  by (unfold_locales, metis, simp)
end
locale spanning_tree = ulgraph V E + T: tree V T for V E T +
  assumes subgraph: "T ⊆ E"
lemma (in fin_connected_ulgraph) has_spanning_tree: "∃T. spanning_tree V E T"
  using fin_connected_ulgraph_axioms
proof (induction "card E" arbitrary: E)
  case 0
  then interpret g: fin_connected_ulgraph V edges by blast
  have edges: "edges = {}" using g.fin_edges 0 by simp
  then obtain v where V: "V = {v}" using g.V_E_empty by blast
  interpret g': fin_connected_sgraph V edges using g.connected edges by (unfold_locales, auto)
  interpret t: tree V edges using g.length_cycle_card_V g'.cycle2_min_length g.is_cycle2_def V by (unfold_locales, fastforce)
  have "spanning_tree V edges edges" by (unfold_locales, auto) 
  then show ?case by blast
next
  case (Suc m)
  then interpret g: fin_connected_ulgraph V edges by blast
  show ?case
  proof (cases "∀c. ¬g.is_cycle2 c")
    case True
    then have "spanning_tree V edges edges" by (unfold_locales, auto)
    then show ?thesis by blast
  next
    case False
    then obtain c where cycle: "g.is_cycle2 c" by blast
    then have "length c ≥ 2" unfolding g.is_cycle2_def g.is_cycle_alt walk_length_conv by auto
    then obtain u v xs where c: "c = u#v#xs" by (metis Suc_le_length_iff numeral_2_eq_2)
    then have g': "fin_connected_ulgraph V (edges - {{u,v}})" using finV g.connected_remove_cycle_edges
      by (metis connected_ulgraph_def cycle fin_connected_ulgraph_def fin_graph_system.intro fin_graph_system_axioms.intro fin_ulgraph.intro ulgraph_def)
    have "{u,v} ∈ edges" using cycle unfolding c g.is_cycle2_def g.is_cycle_alt g.is_walk_def by auto
    then obtain T where "spanning_tree V (edges - {{u,v}}) T" using Suc card_Diff_singleton g' by fastforce
    then have "spanning_tree V edges T" unfolding spanning_tree_def spanning_tree_axioms_def using g.ulgraph_axioms by blast
    then show ?thesis by blast
  qed
qed
context tree
begin
definition leaf :: "'a ⇒ bool" where
  "leaf v ⟷ degree v = 1"
definition leaves :: "'a set" where
  "leaves = {v. leaf v}"
definition non_trivial :: "bool" where
  "non_trivial ⟷ card V ≥ 2"
lemma obtain_2_verts:
  assumes "non_trivial"
  obtains u v where "u ∈ V" "v ∈ V" "u ≠ v"
  using assms unfolding non_trivial_def
  by (meson diameter_obtains_path_vertices)
lemma leaf_in_V: "leaf v ⟹ v ∈ V"
  unfolding leaf_def using degree_none by force
lemma exists_leaf:
  assumes "non_trivial"
  shows "∃v∈V. leaf v"
proof-
  obtain p where is_path: "is_path p" and longest_path: "∀s. is_path s ⟶ length s ≤ length p"
    using obtain_longest_path 
    by (metis One_nat_def assms connected connected_sgraph_axioms connected_sgraph_def degree_0_not_connected
        is_connected_setD is_edge_or_loop is_isolated_vertex_def is_isolated_vertex_degree0 is_loop_def
        n_not_Suc_n numeral_2_eq_2 obtain_2_verts sgraph.two_edges vert_adj_def)
  then obtain l v xs where p: "p = l#v#xs"
    by (metis is_open_walk_def is_path_def is_walk_not_empty2 last_ConsL list.exhaust_sel)
  then have lv_incident: "{l,v} ∈ incident_edges l" using is_path
    unfolding incident_edges_def vincident_def is_path_def is_open_walk_def is_walk_def by simp
  have "⋀e. e∈E ⟹ e ≠ {l,v} ⟹ e ∉ incident_edges l"
  proof
    fix e
    assume e_in_E: "e ∈ E"
      and not_lv: "e ≠ {l,v}"
      and incident: "e ∈ incident_edges l"
    obtain u where e: "e = {l,u}" using e_in_E obtain_edge_pair_adj incident
      unfolding incident_edges_def vincident_def by auto
    then have "u ≠ l" using e_in_E edge_vertices_not_equal by blast
    have "u ≠ v" using e not_lv by auto
    have u_in_V: "u ∈ V" using e_in_E e wellformed by blast
    then show False
    proof (cases "u ∈ set p")
      case True
      then have "u ∈ set xs" using ‹u≠l› ‹u≠v› p by simp
      then obtain ys zs where "xs = ys@u#zs" by (meson split_list)
      then have "is_cycle2 (u#l#v#ys@[u])"
        using is_path ‹u≠l› ‹u≠v› e_in_E distinct_edgesI walk_edges_append_ss2 walk_edges_in_verts
        unfolding is_cycle2_def is_cycle_def p is_path_def is_closed_walk_def is_open_walk_def is_walk_def e walk_length_conv
        by (auto, metis insert_commute, fastforce+)
      then show ?thesis using no_cycles by blast
    next
      case False
      then have "is_path (u#p)" using is_path u_in_V e_in_E
        unfolding is_path_def is_open_walk_def is_walk_def e p by (auto, (metis insert_commute)+)
      then show False using longest_path by auto
    qed
  qed
  then have "incident_edges l = {{l,v}}" using lv_incident unfolding incident_edges_def by blast
  then have leaf: "leaf l" unfolding leaf_def alt_degree_def by simp
  then show ?thesis using leaf_in_V by blast
qed
lemma tree_remove_leaf:
  assumes leaf: "leaf l"
    and remove_vertex: "remove_vertex l = (V',E')"
  shows "tree V' E'"
proof-
  interpret g': ulgraph V' E' using remove_vertex wellformed edge_size unfolding remove_vertex_def vincident_def
    by (unfold_locales, auto)
  interpret subg: ulsubgraph V' E' V E using subgraph_remove_vertex ulgraph_axioms remove_vertex
    unfolding ulsubgraph_def by blast
  have V': "V' = V - {l}" using remove_vertex unfolding remove_vertex_def by blast
  have E': "E' = {e∈E. l ∉ e}" using remove_vertex unfolding remove_vertex_def vincident_def by blast
  have "∃v∈V. v ≠ l" using leaf unfolding leaf_def
    by (metis One_nat_def is_independent_alt is_isolated_vertex_def is_isolated_vertex_degree0
        n_not_Suc_n radius_obtains singletonI singleton_independent_set)
  then have "V' ≠ {}" using remove_vertex unfolding remove_vertex_def vincident_def by blast
  then have "g'.is_connected_set V'" using connected_remove_leaf leaf remove_vertex unfolding leaf_def by blast
  then show ?thesis using ‹V'≠{}› finV subg.is_cycle2 V' E' no_cycles by (unfold_locales, auto)
qed
end
lemma tree_induct [case_names singolton insert, induct set: tree]:
  assumes tree: "tree V E"
    and trivial: "⋀v. tree {v} {} ⟹ P {v} {}"
    and insert: "⋀l v V E. tree V E ⟹ P V E ⟹ l ∉ V ⟹ v ∈ V ⟹ {l,v} ∉ E ⟹ tree.leaf (insert {l,v} E) l ⟹ P (insert l V) (insert {l,v} E)"
  shows "P V E"
  using tree
proof (induction "card V" arbitrary: V E)
  case 0
  then interpret tree V E by simp
  have "V = {}" using finV 0(1) by simp
  then show ?case using not_empty by blast
next
  case (Suc n)
  then interpret t: tree V E by simp
  show ?case
  proof (cases "card V = 1")
    case True
    then obtain v where V: "V = {v}" using card_1_singletonE by blast
    then have "E = {}"
      using True subset_antisym t.edge_incident_vert t.vincident_def t.singleton_not_edge t.wellformed
      by fastforce
    then show ?thesis using trivial t.tree_axioms V by simp
  next
    case False
    then have card_V: "card V ≥ 2" using Suc by simp
    then obtain l where leaf: "t.leaf l" using t.exists_leaf t.non_trivial_def by blast
    then obtain e where inc_edges: "t.incident_edges l = {e}"
      unfolding t.leaf_def t.alt_degree_def using card_1_singletonE by blast
    then have e_in_E: "e ∈ E" unfolding t.incident_edges_def by blast
    then obtain u where e: "e = {l,u}" using t.two_edges card_2_iff inc_edges unfolding t.incident_edges_def t.vincident_def
      by (metis (no_types, lifting) empty_iff insert_commute insert_iff mem_Collect_eq)
    then have "l ≠ u" using e_in_E t.edge_vertices_not_equal by blast
    have "u ∈ V" using e e_in_E t.wellformed by blast
    let ?V' = "V - {l}"
    let ?E' = "E - {{l,u}}"
    have remove_vertex: "t.remove_vertex l = (?V', ?E')"
      using inc_edges e unfolding t.remove_vertex_def t.incident_edges_def by blast
    then have t': "tree ?V' ?E'" using t.tree_remove_leaf leaf by blast
    have "l ∈ V" using leaf t.leaf_in_V by blast
    then have P': "P ?V' ?E'" using Suc t' by auto
    show ?thesis using insert[OF t' P'] Suc leaf ‹u∈V› ‹l≠u› ‹l ∈ V› e e_in_E by (auto, metis insert_Diff)
  qed
qed
context tree
begin
lemma card_V_card_E: "card V = Suc (card E)"
  using tree_axioms
proof (induction V E)
  case (singolton v)
  then show ?case by auto
next
  case (insert l v V' E')
  then interpret t': tree V' E' by simp
  show ?case using t'.finV t'.fin_edges insert by simp
qed
end
lemma card_E_treeI:
  assumes fin_conn_sgraph: "fin_connected_ulgraph V E"
    and card_V_E: "card V = Suc (card E)"
  shows "tree V E"
proof-
  interpret G: fin_connected_ulgraph V E using fin_conn_sgraph .
  obtain T where T: "spanning_tree V E T" using G.has_spanning_tree by blast
  show ?thesis
  proof (cases "E = T")
    case True
    then show ?thesis using T unfolding spanning_tree_def by blast
  next
    case False
    then have "card E > card T" using T G.fin_edges unfolding spanning_tree_def spanning_tree_axioms_def
      by (simp add: psubsetI psubset_card_mono)
    then show ?thesis using tree.card_V_card_E T card_V_E unfolding spanning_tree_def by fastforce
  qed
qed
context tree
begin
lemma add_vertex_tree:
  assumes "v ∉ V"
    and  "w ∈ V"
  shows "tree (insert v V) (insert {v,w} E)"
proof -
  let ?V' = "insert v V" and ?E' = "insert {v,w} E"
  have cardV: "card {v,w} = 2" using card_2_iff assms by auto
  then interpret t': ulgraph ?V' ?E'
    using wellformed assms two_edges by (unfold_locales, auto)
  interpret subg: ulsubgraph V E ?V' ?E' by (unfold_locales, auto)
  have connected: "t'.is_connected_set ?V'"
    unfolding t'.is_connected_set_def
    using subg.vert_connected t'.vert_connected_neighbors t'.vert_connected_trans
      t'.vert_connected_id vertices_connected t'.ulgraph_axioms ulgraph_axioms assms t'.vert_connected_rev
    by simp metis
  then have fin_connected_ulgraph: "fin_connected_ulgraph ?V' ?E'" using finV by (unfold_locales, auto)
  from assms have "{v,w} ∉ E" using wellformed_alt_fst by auto
  then have "card ?E' = Suc (card E)" using fin_edges card_insert_if by auto
  then have "card ?V' = Suc (card ?E')" using card_V_card_E assms wellformed_alt_fst finV card_insert_if by auto
  then show ?thesis using card_E_treeI fin_connected_ulgraph by auto
qed
lemma tree_connected_set:
  assumes non_empty: "V' ≠ {}"
    and subg: "V' ⊆ V"
    and connected_V': "ulgraph.is_connected_set V' (induced_edges V') V'"
  shows "tree V' (induced_edges V')"
proof-
  interpret subg: subgraph V' "induced_edges V'" V E using induced_is_subgraph subg by simp
  interpret g': ulgraph V' "induced_edges V'" using subg.is_subgraph_ulgraph ulgraph_axioms by blast
  interpret subg: ulsubgraph V' "induced_edges V'" V E by unfold_locales
  show ?thesis using connected_V' subg.is_cycle2 no_cycles finV subg non_empty rev_finite_subset by (unfold_locales) (auto, blast)
qed
lemma unique_adj_vert_removed:
  assumes "v ∈ V"
    and remove_vertex: "remove_vertex v = (V',E')"
    and conn_component: "C ∈ ulgraph.connected_components V' E'"
  shows "∃!u∈C. vert_adj v u"
proof-
  interpret subg: ulsubgraph V' E' V E using remove_vertex subgraph_remove_vertex ulgraph_axioms ulsubgraph.intro by metis
  interpret g': ulgraph V' E' using subg.is_subgraph_ulgraph ulgraph_axioms by simp
  obtain u where "u ∈ C" and adj_vu: "vert_adj v u" using exists_adj_vert_removed using assms by blast
  have "w = u" if "w ∈ C" and adj_vw: "vert_adj v w" for w
  proof (rule ccontr)
    assume "w ≠ u"
    obtain p where g'_conn_path: "g'.connecting_path w u p" using ‹u∈C› ‹w∈C› conn_component
        g'.connected_component_connected g'.is_connected_setD g'.vert_connected_def by blast
    then have v_notin_p: "v ∉ set p" using remove_vertex unfolding g'.connecting_path_def g'.is_gen_path_def g'.is_walk_def remove_vertex_def by blast
    have conn_path: "connecting_path w u p" using g'_conn_path subg.connecting_path by simp
    then obtain p' where p: "p = w # p' @ [u]" unfolding connecting_path_def using ‹w≠u›
      by (metis hd_Cons_tl last.simps last_rev rev_is_Nil_conv snoc_eq_iff_butlast)
    then have "walk_edges (v#p@[v]) = {v,w} # walk_edges ((w # p') @ [u,v])" by simp
    also have "… = {v,w} # walk_edges p @ [{u,v}]" unfolding p using walk_edges_app by (metis Cons_eq_appendI)
    finally have walk_edges: "walk_edges (v#p@[v]) = {v,w} # walk_edges p @ [{v,u}]" by (simp add: insert_commute)
    then have "is_cycle (v#p@[v])" using conn_path adj_vu adj_vw ‹w≠u› ‹v∈V› g'.walk_length_conv singleton_not_edge v_notin_p
      unfolding connecting_path_def is_cycle_def is_gen_path_def is_closed_walk_def is_walk_def p vert_adj_def by auto
    then have "is_cycle2 (v#p@[v])" using ‹w≠u› v_notin_p walk_edges_in_verts unfolding is_cycle2_def walk_edges
      by (auto simp: doubleton_eq_iff is_cycle_alt distinct_edgesI)
    then show False using no_cycles by blast
  qed
  then show ?thesis using ‹u∈C› adj_vu by blast
qed
lemma non_trivial_card_E: "non_trivial ⟹ card E ≥ 1"
  using card_V_card_E unfolding non_trivial_def by simp
lemma V_Union_E: "non_trivial ⟹ V = ⋃E"
  using tree_axioms
proof (induction V E)
  case (singolton v) 
  then interpret t: tree "{v}" "{}" by simp
  show ?case using singolton unfolding t.non_trivial_def by simp
next
  case (insert l v V' E')
  then interpret t: tree V' E' by simp
  show ?case
  proof (cases "card V' = 1")
    case True
    then have V: "V' = {v}" using insert(3) card_1_singletonE by blast
    then have E: "E' = {}" using t.fin_edges t.card_V_card_E by fastforce
    then show ?thesis unfolding E V by simp
  next
    case False
    then have "t.non_trivial" using t.card_V_card_E unfolding t.non_trivial_def by simp
    then show ?thesis using insert by blast
  qed
qed
end
lemma singleton_tree: "tree {v} {}"
proof-
  interpret g: fin_ulgraph "{v}" "{}" by (unfold_locales, auto)
  show ?thesis using g.is_walk_def g.walk_length_def by (unfold_locales, auto simp: g.is_connected_set_singleton g.is_cycle2_def g.is_cycle_alt)
qed
lemma tree2:
  assumes "u ≠ v"
    shows "tree {u,v} {{u,v}}"
proof-
  interpret ulgraph "{u,v}" "{{u,v}}" using ‹u≠v› by unfold_locales auto
  have "fin_connected_ulgraph {u,v} {{u,v}}" by unfold_locales
    (auto simp: is_connected_set_def vert_connected_id vert_connected_neighbors vert_connected_rev)
  then show ?thesis using card_E_treeI ‹u≠v› by fastforce
qed
subsection ‹Graph Isomorphism›
locale graph_isomorphism =
  G: graph_system V⇩G E⇩G for V⇩G E⇩G +
  fixes V⇩H E⇩H f
  assumes bij_f: "bij_betw f V⇩G V⇩H"
  and edge_preserving: "((`) f) ` E⇩G = E⇩H"
begin
lemma inj_f: "inj_on f V⇩G"
  using bij_f unfolding bij_betw_def by blast
lemma V⇩H_def: "V⇩H = f ` V⇩G"
  using bij_f unfolding bij_betw_def by blast
definition "inv_iso ≡ the_inv_into V⇩G f"
lemma graph_system_H: "graph_system V⇩H E⇩H"
  using G.wellformed edge_preserving bij_f bij_betw_imp_surj_on by unfold_locales blast
interpretation H: graph_system V⇩H E⇩H using graph_system_H .
lemma graph_isomorphism_inv: "graph_isomorphism V⇩H E⇩H V⇩G E⇩G inv_iso"
proof (unfold_locales)
  show "bij_betw inv_iso V⇩H V⇩G" unfolding inv_iso_def using bij_betw_the_inv_into bij_f by blast
next
  have "∀v∈V⇩G. the_inv_into V⇩G f (f v) = v" using bij_f by (simp add: bij_betw_imp_inj_on the_inv_into_f_f)
  then have "∀e∈E⇩G. (λv. the_inv_into V⇩G f (f v)) ` e = e" using G.wellformed
    by (simp add: subset_iff)
  then show "((`) inv_iso)` E⇩H = E⇩G" unfolding inv_iso_def by (simp add: edge_preserving[symmetric] image_comp)
qed
interpretation inv_iso: graph_isomorphism V⇩H E⇩H V⇩G E⇩G inv_iso using graph_isomorphism_inv .
end
fun graph_isomorph :: "'a pregraph ⇒ 'b pregraph ⇒ bool" (infix ‹≃› 50) where
  "(V⇩G,E⇩G) ≃ (V⇩H,E⇩H) ⟷ (∃f. graph_isomorphism V⇩G E⇩G V⇩H E⇩H f)"
lemma (in graph_system) graph_isomorphism_id: "graph_isomorphism V E V E id"
  by unfold_locales auto
lemma (in graph_system) graph_isomorph_refl: "(V,E) ≃ (V,E)"
  using graph_isomorphism_id by auto
lemma graph_isomorph_sym: "symp (≃)"
  using graph_isomorphism.graph_isomorphism_inv unfolding symp_def by fastforce
lemma graph_isomorphism_trans: "graph_isomorphism V⇩G E⇩G V⇩H E⇩H f ⟹ graph_isomorphism V⇩H E⇩H V⇩F E⇩F g ⟹ graph_isomorphism V⇩G E⇩G V⇩F E⇩F (g o f)"
  unfolding graph_isomorphism_def graph_isomorphism_axioms_def using bij_betw_trans by (auto, blast)
lemma graph_isomorph_trans: "transp (≃)"
  using graph_isomorphism_trans unfolding transp_def by fastforce
end