(* Title: Euler.thy Author: Lars Noschinski, TU München *) theory Euler imports Arc_Walk Digraph_Component Digraph_Isomorphism begin section ‹Euler Trails in Digraphs› text ‹ In this section we prove the well-known theorem characterizing the existence of an Euler Trail in an directed graph › subsection ‹Trails and Euler Trails› definition (in pre_digraph) euler_trail :: "'a ⇒ 'b awalk ⇒ 'a ⇒ bool" where "euler_trail u p v ≡ trail u p v ∧ set p = arcs G ∧ set (awalk_verts u p) = verts G" context wf_digraph begin (* XXX move; notused*) lemma finite_distinct: assumes "finite A" shows "finite {p. distinct p ∧ set p ⊆ A}" proof - have "{p. distinct p ∧ set p ⊆ A} ⊆ {p. set p ⊆ A ∧ length p ≤ card A}" using assms by (auto simp: distinct_card[symmetric] intro: card_mono) also have "finite ..." using assms by (simp add: finite_lists_length_le) finally (finite_subset) show ?thesis . qed (* XXX move; notused*) lemma (in fin_digraph) trails_finite: "finite {p. ∃u v. trail u p v}" proof - have "{p. ∃u v. trail u p v} ⊆ {p. distinct p ∧ set p ⊆ arcs G}" by (auto simp: trail_def) with finite_arcs finite_distinct show ?thesis by (blast intro: finite_subset) qed (* XXX: simplify apath_finite proof? *) lemma rotate_awalkE: assumes "awalk u p u" "w ∈ set (awalk_verts u p)" obtains q r where "p = q @ r" "awalk w (r @ q) w" "set (awalk_verts w (r @ q)) = set (awalk_verts u p)" proof - from assms obtain q r where A: "p = q @ r" and A': "awalk u q w" "awalk w r u" by atomize_elim (rule awalk_decomp) then have B: "awalk w (r @ q) w" by auto have C: "set (awalk_verts w (r @ q)) = set (awalk_verts u p)" using ‹awalk u p u› A A' by (auto simp: set_awalk_verts_append) from A B C show ?thesis .. qed lemma rotate_trailE: assumes "trail u p u" "w ∈ set (awalk_verts u p)" obtains q r where "p = q @ r" "trail w (r @ q) w" "set (awalk_verts w (r @ q)) = set (awalk_verts u p)" using assms by - (rule rotate_awalkE[where u=u and p=p and w=w], auto simp: trail_def) lemma rotate_trailE': assumes "trail u p u" "w ∈ set (awalk_verts u p)" obtains q where "trail w q w" "set q = set p" "set (awalk_verts w q) = set (awalk_verts u p)" proof - from assms obtain q r where "p = q @ r" "trail w (r @ q) w" "set (awalk_verts w (r @ q)) = set (awalk_verts u p)" by (rule rotate_trailE) then have "set (r @ q) = set p" by auto show ?thesis by (rule that) fact+ qed lemma sym_reachableI_in_awalk: assumes walk: "awalk u p v" and w1: "w1 ∈ set (awalk_verts u p)" and w2: "w2 ∈ set (awalk_verts u p)" shows "w1 →⇧^{*}⇘mk_symmetric G⇙ w2" proof - from walk w1 obtain q r where "p = q @ r" "awalk u q w1" "awalk w1 r v" by (atomize_elim) (rule awalk_decomp) then have w2_in: "w2 ∈ set (awalk_verts u q) ∪ set (awalk_verts w1 r)" using w2 by (auto simp: set_awalk_verts_append) show ?thesis proof cases assume A: "w2 ∈ set (awalk_verts u q)" obtain s where "awalk w2 s w1" using awalk_decomp[OF ‹awalk u q w1› A] by blast then have "w2 →⇧^{*}⇘mk_symmetric G⇙ w1" by (intro reachable_awalkI reachable_mk_symmetricI) with symmetric_mk_symmetric show ?thesis by (rule symmetric_reachable) next assume "w2 ∉ set (awalk_verts u q)" then have A: "w2 ∈ set (awalk_verts w1 r)" using w2_in by blast obtain s where "awalk w1 s w2" using awalk_decomp[OF ‹awalk w1 r v› A] by blast then show "w1 →⇧^{*}⇘mk_symmetric G⇙ w2" by (intro reachable_awalkI reachable_mk_symmetricI) qed qed lemma euler_imp_connected: assumes "euler_trail u p v" shows "connected G" proof - { have "verts G ≠ {}" using assms unfolding euler_trail_def trail_def by auto } moreover { fix w1 w2 assume "w1 ∈ verts G" "w2 ∈ verts G" then have "awalk u p v " "w1 ∈ set (awalk_verts u p)" "w2 ∈ set (awalk_verts u p)" using assms by (auto simp: euler_trail_def trail_def) then have "w1 →⇧^{*}⇘mk_symmetric G⇙ w2" by (rule sym_reachableI_in_awalk) } ultimately show "connected G" by (rule connectedI) qed end subsection ‹Arc Balance of Walks› context pre_digraph begin (* XXX change order of arguments? *) definition arc_set_balance :: "'a ⇒ 'b set ⇒ int" where "arc_set_balance w A = int (card (in_arcs G w ∩ A)) - int (card (out_arcs G w ∩ A))" definition arc_set_balanced :: "'a ⇒ 'b set ⇒ 'a ⇒ bool" where "arc_set_balanced u A v ≡ if u = v then (∀w ∈ verts G. arc_set_balance w A = 0) else (∀w ∈ verts G. (w ≠ u ∧ w ≠ v) ⟶ arc_set_balance w A = 0) ∧ arc_set_balance u A = -1 ∧ arc_set_balance v A = 1" abbreviation arc_balance :: "'a ⇒ 'b awalk ⇒ int" where "arc_balance w p ≡ arc_set_balance w (set p)" abbreviation arc_balanced :: "'a ⇒ 'b awalk ⇒ 'a ⇒ bool" where "arc_balanced u p v ≡ arc_set_balanced u (set p) v" lemma arc_set_balanced_all: "arc_set_balanced u (arcs G) v = (if u = v then (∀w ∈ verts G. in_degree G w = out_degree G w) else (∀w ∈ verts G. (w ≠ u ∧ w ≠ v) ⟶ in_degree G w = out_degree G w) ∧ in_degree G u + 1 = out_degree G u ∧ out_degree G v + 1 = in_degree G v)" unfolding arc_set_balanced_def arc_set_balance_def in_degree_def out_degree_def by auto end context wf_digraph begin (* XXX tune assumption? e ∉ set es oder so? *) lemma arc_balance_Cons: assumes "trail u (e # es) v" shows "arc_set_balance w (insert e (set es)) = arc_set_balance w {e} + arc_balance w es" proof - from assms have "e ∉ set es" "e ∈ arcs G" by (auto simp: trail_def) with ‹e ∉ set es› show ?thesis apply (cases "w = tail G e") apply (case_tac [!] "w = head G e") apply (auto simp: arc_set_balance_def) done qed lemma arc_balancedI_trail: assumes "trail u p v" shows "arc_balanced u p v" using assms proof (induct p arbitrary: u) case Nil then show ?case by (auto simp: arc_set_balanced_def arc_set_balance_def trail_def) next case (Cons e es) then have "arc_balanced (head G e) es v" "u = tail G e" "e ∈ arcs G" by (auto simp: awalk_Cons_iff trail_def) moreover have "⋀w. arc_balance w [e] = (if w = tail G e ∧ tail G e ≠ head G e then -1 else if w = head G e ∧ tail G e ≠ head G e then 1 else 0)" using ‹e ∈ _› by (case_tac "w = tail G e") (auto simp: arc_set_balance_def) ultimately show ?case by (auto simp: arc_set_balanced_def arc_balance_Cons[OF ‹trail u _ _›]) qed lemma trail_arc_balanceE: assumes "trail u p v" obtains "⋀w. ⟦ u = v ∨ (w ≠ u ∧ w ≠ v); w ∈ verts G ⟧ ⟹ arc_balance w p = 0" and "⟦ u ≠ v ⟧ ⟹ arc_balance u p = - 1" and "⟦ u ≠ v ⟧ ⟹ arc_balance v p = 1" using arc_balancedI_trail[OF assms] unfolding arc_set_balanced_def by (intro that) (metis,presburger+) end subsection ‹Closed Euler Trails› lemma (in wf_digraph) awalk_vertex_props: assumes "awalk u p v" "p ≠ []" assumes "⋀w. w ∈ set (awalk_verts u p) ⟹ P w ∨ Q w" assumes "P u" "Q v" shows "∃e ∈ set p. P (tail G e) ∧ Q (head G e)" using assms(2,1,3-) proof (induct p arbitrary: u rule: list_nonempty_induct) case (cons e es) show ?case proof (cases "P (tail G e) ∧ Q (head G e)") case False then have "P (head G e) ∨ Q (head G e)" using cons.prems(1) cons.prems(2)[of "head G e"] by (auto simp: awalk_Cons_iff set_awalk_verts) then have "P (tail G e) ∧ P (head G e)" using False using cons.prems(1,3) by auto then have "∃e ∈ set es. P (tail G e) ∧ Q (head G e)" using cons by (auto intro: cons simp: awalk_Cons_iff) then show ?thesis by auto qed auto qed (simp add: awalk_simps) lemma (in wf_digraph) connected_verts: assumes "connected G" "arcs G ≠ {}" shows "verts G = tail G ` arcs G ∪ head G ` arcs G" proof - { assume "verts G = {}" then have ?thesis by (auto dest: tail_in_verts) } moreover { assume "∃v. verts G = {v}" then obtain v where "verts G = {v}" by (auto simp: card_Suc_eq) moreover with ‹arcs G ≠ {}› obtain e where "e ∈ arcs G" "tail G e = v" "head G e = v" by (auto dest: tail_in_verts head_in_verts) moreover have "tail G ` arcs G ∪ head G ` arcs G ⊆ verts G" by auto ultimately have ?thesis by auto } moreover { assume A: "∃u v. u ∈ verts G ∧ v ∈ verts G ∧ u ≠ v" { fix u assume "u ∈ verts G" interpret S: pair_wf_digraph "mk_symmetric G" by rule from A obtain v where "v ∈ verts G" "u ≠ v" by blast then obtain p where "S.awalk u p v" using ‹connected G› ‹u ∈ verts G› by (auto elim: connected_awalkE) with ‹u ≠ v› obtain e where "e ∈ parcs (mk_symmetric G)" "fst e = u" by (metis S.awalk_Cons_iff S.awalk_empty_ends list_exhaust2) then obtain e' where "tail G e' = u ∨ head G e' = u" "e' ∈ arcs G" by (force simp: parcs_mk_symmetric) then have "u ∈ tail G ` arcs G ∪ head G `arcs G" by auto } then have ?thesis by auto } ultimately show ?thesis by blast qed lemma (in wf_digraph) connected_arcs_empty: assumes "connected G" "arcs G = {}" "verts G ≠ {}" obtains v where "verts G = {v}" proof (atomize_elim, rule ccontr) assume A: "¬ (∃v. verts G = {v})" interpret S: pair_wf_digraph "mk_symmetric G" by rule from ‹verts G ≠ {}› obtain u where "u ∈ verts G" by auto with A obtain v where "v ∈ verts G" "u ≠ v" by auto from ‹connected G› ‹u ∈ verts G› ‹v ∈ verts G› obtain p where "S.awalk u p v" using ‹connected G› ‹u ∈ verts G› by (auto elim: connected_awalkE) with ‹u ≠ v› obtain e where "e ∈ parcs (mk_symmetric G)" by (metis S.awalk_Cons_iff S.awalk_empty_ends list_exhaust2) with ‹arcs G = {}› show False by (auto simp: parcs_mk_symmetric) qed lemma (in wf_digraph) euler_trail_conv_connected: assumes "connected G" shows "euler_trail u p v ⟷ trail u p v ∧ set p = arcs G" (is "?L ⟷ ?R") proof assume ?R show ?L proof cases assume "p = []" with assms ‹?R› show ?thesis by (auto simp: euler_trail_def trail_def awalk_def elim: connected_arcs_empty) next assume "p ≠ []" then have "arcs G ≠ {}" using ‹?R› by auto with assms ‹?R› ‹p ≠ []› show ?thesis by (auto simp: euler_trail_def trail_def set_awalk_verts_not_Nil connected_verts) qed qed (simp add: euler_trail_def) lemma (in wf_digraph) awalk_connected: assumes "connected G" "awalk u p v" "set p ≠ arcs G" shows "∃e. e ∈ arcs G - set p ∧ (tail G e ∈ set (awalk_verts u p) ∨ head G e ∈ set (awalk_verts u p))" proof (rule ccontr) assume A: "¬?thesis" obtain e where "e ∈ arcs G - set p" using assms by (auto simp: trail_def) with A have "tail G e ∉ set (awalk_verts u p)" "tail G e ∈ verts G" by auto interpret S: pair_wf_digraph "mk_symmetric G" .. have "u ∈ verts G" using ‹awalk u p v› by (auto simp: awalk_hd_in_verts) with ‹tail G e ∈ _› and ‹connected G› obtain q where q: "S.awalk u q (tail G e)" by (auto elim: connected_awalkE) have "u ∈ set (awalk_verts u p)" using ‹awalk u p v› by (auto simp: set_awalk_verts) have "q ≠ []" using ‹u ∈ set _› ‹tail G e ∉ _› q by auto have "∃e ∈ set q. fst e ∈ set (awalk_verts u p) ∧ snd e ∉ set (awalk_verts u p)" by (rule S.awalk_vertex_props[OF ‹S.awalk _ _ _› ‹q ≠ []›]) (auto simp: ‹u ∈ set _› ‹tail G e ∉ _›) then obtain se' where se': "se' ∈ set q" "fst se' ∈ set (awalk_verts u p)" "snd se' ∉ set (awalk_verts u p)" by auto from se' have "se' ∈ parcs (mk_symmetric G)" using q by auto then obtain e' where "e' ∈ arcs G" "(tail G e' = fst se' ∧ head G e' = snd se') ∨ (tail G e' = snd se' ∧ head G e' = fst se')" by (auto simp: parcs_mk_symmetric) moreover then have "e' ∉ set p" using se' ‹awalk u p v› by (auto dest: awalk_verts_arc2 awalk_verts_arc1) ultimately show False using se' using A by auto qed lemma (in wf_digraph) trail_connected: assumes "connected G" "trail u p v" "set p ≠ arcs G" shows "∃e. e ∈ arcs G - set p ∧ (tail G e ∈ set (awalk_verts u p) ∨ head G e ∈ set (awalk_verts u p))" using assms by (intro awalk_connected) (auto simp: trail_def) theorem (in fin_digraph) closed_euler1: assumes con: "connected G" assumes deg: "⋀u. u ∈ verts G ⟹ in_degree G u = out_degree G u" shows "∃u p. euler_trail u p u" proof - from con obtain u where "u ∈ verts G" by (auto simp: connected_def strongly_connected_def) then have "trail u [] u" by (auto simp: trail_def awalk_simps) moreover { fix u p v assume "trail u p v" then have "∃u' p' v'. euler_trail u' p' v'" proof (induct "card (arcs G) - length p" arbitrary: u p v) case 0 then have "u ∈ verts G" by (auto simp: trail_def) have "set p ⊆ arcs G" using ‹trail u p v› by (auto simp: trail_def) with 0 have "set p = arcs G" by (auto simp: trail_def distinct_card[symmetric] card_seteq) then have "euler_trail u p v" using 0 by (simp add: euler_trail_conv_connected[OF con]) then show ?case by blast next case (Suc n) then have neq: "set p ≠ arcs G" "u ∈ verts G" by (auto simp: trail_def distinct_card[symmetric]) show ?case proof (cases "u = v") assume "u ≠ v" then have "arc_balance u p = -1" using Suc neq by (auto elim: trail_arc_balanceE) then have "card (in_arcs G u ∩ set p) < card (out_arcs G u ∩ set p)" unfolding arc_set_balance_def by auto also have "… ≤ card (out_arcs G u)" by (rule card_mono) auto finally have "card (in_arcs G u ∩ set p) < card (in_arcs G u)" using deg[OF ‹u ∈ _›] unfolding out_degree_def in_degree_def by simp then have "in_arcs G u - set p ≠ {}" by (auto dest: card_psubset[rotated 2]) then obtain a where "a ∈ arcs G" "head G a = u" "a ∉ set p" by (auto simp: in_arcs_def) then have *: "trail (tail G a) (a # p) v" using Suc by (auto simp: trail_def awalk_simps) then show ?thesis using Suc by (intro Suc) auto next assume "u = v" with neq con Suc obtain a where a_in: "a ∈ arcs G - set p" and a_end: "(tail G a ∈ set (awalk_verts u p) ∨ head G a ∈ set (awalk_verts u p))" by (atomize_elim) (rule trail_connected) have "trail u p u" using Suc ‹u = v› by simp show ?case proof (cases "tail G a ∈ set (awalk_verts u p)") case True with ‹trail u p u› obtain q where q: "set p = set q" "trail (tail G a) q (tail G a)" by (rule rotate_trailE') blast with True a_in have *: "trail (tail G a) (q @ [a]) (head G a)" by (fastforce simp: trail_def awalk_simps ) moreover from q Suc have "length q = length p" by (simp add: trail_def distinct_card[symmetric]) ultimately show ?thesis using Suc by (intro Suc) auto next case False with a_end have "head G a ∈ set (awalk_verts u p)" by blast with ‹trail u p u› obtain q where q: "set p = set q" "trail (head G a) q (head G a)" by (rule rotate_trailE') blast with False a_in have *: "trail (tail G a) (a # q) (head G a)" by (fastforce simp: trail_def awalk_simps ) moreover from q Suc have "length q = length p" by (simp add: trail_def distinct_card[symmetric]) ultimately show ?thesis using Suc by (intro Suc) auto qed qed qed } ultimately obtain u p v where et: "euler_trail u p v" by blast moreover have "u = v" proof - have "arc_balanced u p v" using ‹euler_trail u p v› by (auto simp: euler_trail_def dest: arc_balancedI_trail) then show ?thesis using ‹euler_trail u p v› deg by (auto simp add: euler_trail_def trail_def arc_set_balanced_all split: if_split_asm) qed ultimately show ?thesis by blast qed lemma (in wf_digraph) closed_euler_imp_eq_degree: assumes "euler_trail u p u" assumes "v ∈ verts G" shows "in_degree G v = out_degree G v" proof - from assms have "arc_balanced u p u" "set p = arcs G" unfolding euler_trail_def by (auto dest: arc_balancedI_trail) with assms have "arc_balance v p = 0" unfolding arc_set_balanced_def by auto moreover from ‹set p = _› have "in_arcs G v ∩ set p = in_arcs G v" "out_arcs G v ∩ set p = out_arcs G v" by (auto intro: in_arcs_in_arcs out_arcs_in_arcs) ultimately show ?thesis unfolding arc_set_balance_def in_degree_def out_degree_def by auto qed theorem (in fin_digraph) closed_euler2: assumes "euler_trail u p u" shows "connected G" and "⋀u. u ∈ verts G ⟹ in_degree G u = out_degree G u" (is "⋀u. _ ⟹ ?eq_deg u") proof - from assms show "connected G" by (rule euler_imp_connected) next fix v assume A: "v ∈ verts G" with assms show "?eq_deg v" by (rule closed_euler_imp_eq_degree) qed corollary (in fin_digraph) closed_euler: "(∃u p. euler_trail u p u) ⟷ connected G ∧ (∀u ∈ verts G. in_degree G u = out_degree G u)" by (auto dest: closed_euler1 closed_euler2) subsection ‹Open euler trails› text ‹ Intuitively, a graph has an open euler trail if and only if it is possible to add an arc such that the resulting graph has a closed euler trail. However, this is not true in our formalization, as the arc type @{typ 'b} might be finite: Consider for example the graph @{term "⦇ verts = {0,1}, arcs = {()}, tail = λ_. 0, head = λ_. 1 ⦈"}. This graph obviously has an open euler trail, but we cannot add another arc, as we already exhausted the universe. However, for each @{term "fin_digraph G"} there exist an isomorphic graph @{term H} with arc type @{typ "'a × nat × 'a"}. Hence, we first characterize the existence of euler trail for the infinite arc type @{typ "'a × nat × 'a"} and transfer that result back to arbitrary arc types. › lemma open_euler_infinite_label: fixes G :: "('a, 'a × nat × 'a) pre_digraph" assumes "fin_digraph G" assumes [simp]: "tail G = fst" "head G = snd o snd" assumes con: "connected G" assumes uv: "u ∈ verts G" "v ∈ verts G" assumes deg: "⋀w. ⟦w ∈ verts G; u ≠ w; v ≠ w⟧ ⟹ in_degree G w = out_degree G w" assumes deg_in: "in_degree G u + 1 = out_degree G u" assumes deg_out: "out_degree G v + 1 = in_degree G v" shows "∃p. pre_digraph.euler_trail G u p v" proof - define label :: "'a × nat × 'a ⇒ nat" where [simp]: "label = fst o snd" interpret fin_digraph G by fact have "finite (label ` arcs G)" by auto moreover have "¬finite (UNIV :: nat set)" by blast ultimately obtain l where "l ∉ label ` arcs G" by atomize_elim (rule ex_new_if_finite) from deg_in deg_out have "u ≠ v" by auto let ?e = "(v,l,u)" have e_notin:"?e ∉ arcs G" using ‹l ∉ _› by (auto simp: image_def) let ?H = "add_arc ?e" ― ‹We define a graph which has an closed euler trail› have [simp]: "verts ?H = verts G" using uv by simp have [intro]: "⋀a. compatible (add_arc a) G" by (simp add: compatible_def) interpret H: fin_digraph "add_arc a" rewrites "tail (add_arc a) = tail G" and "head (add_arc a) = head G" and "pre_digraph.cas (add_arc a) = cas" and "pre_digraph.awalk_verts (add_arc a) = awalk_verts" for a by unfold_locales (auto dest: wellformed intro: compatible_cas compatible_awalk_verts simp: verts_add_arc_conv) have "∃u p. H.euler_trail ?e u p u" proof (rule H.closed_euler1) show "connected ?H" proof (rule H.connectedI) interpret sH: pair_fin_digraph "mk_symmetric ?H" .. fix u v assume "u ∈ verts ?H" "v ∈ verts ?H" with con have "u →⇧^{*}⇘mk_symmetric G⇙ v" by (auto simp: connected_def) moreover have "subgraph G ?H" by (auto simp: subgraph_def) unfold_locales ultimately show "u →⇧^{*}⇘with_proj (mk_symmetric ?H)⇙ v" by (blast intro: sH.reachable_mono subgraph_mk_symmetric) qed (simp add: verts_add_arc_conv) next fix w assume "w ∈ verts ?H" then show "in_degree ?H w = out_degree ?H w" using deg deg_in deg_out e_notin apply (cases "w = u") apply (case_tac [!] "w = v") by (auto simp: in_degree_add_arc_iff out_degree_add_arc_iff) qed then obtain w p where Het: "H.euler_trail ?e w p w" by blast then have "?e ∈ set p" by (auto simp: pre_digraph.euler_trail_def) then obtain q r where p_decomp: "p = q @ [?e] @ r" by (auto simp: in_set_conv_decomp) ― ‹We show now that removing the additional arc of @{term ?H} from p yields an euler trail in G› have "euler_trail u (r @ q) v" proof (unfold euler_trail_conv_connected[OF con], intro conjI) from Het have Ht': "H.trail ?e v (?e # r @ q) v" unfolding p_decomp H.euler_trail_def H.trail_def by (auto simp: p_decomp H.awalk_Cons_iff) then have "H.trail ?e u (r @ q) v" "?e ∉ set (r @ q)" by (auto simp: H.trail_def H.awalk_Cons_iff) then show t': "trail u (r @ q) v" by (auto simp: trail_def H.trail_def awalk_def H.awalk_def) show "set (r @ q) = arcs G" proof - have "arcs G = arcs ?H - {?e}" using e_notin by auto also have "arcs ?H = set p" using Het by (auto simp: pre_digraph.euler_trail_def pre_digraph.trail_def) finally show ?thesis using ‹?e ∉ set _› by (auto simp: p_decomp) qed qed then show ?thesis by blast qed context wf_digraph begin lemma trail_app_isoI: assumes t: "trail u p v" and hom: "digraph_isomorphism hom" shows "pre_digraph.trail (app_iso hom G) (iso_verts hom u) (map (iso_arcs hom) p) (iso_verts hom v)" proof - interpret H: wf_digraph "app_iso hom G" using hom .. from t hom have i: "inj_on (iso_arcs hom) (set p)" unfolding trail_def digraph_isomorphism_def by (auto dest:subset_inj_on[where A="set p"]) then have "distinct (map (iso_arcs hom) p) = distinct p" by (auto simp: distinct_map dest: inj_onD) with t hom show ?thesis by (auto simp: pre_digraph.trail_def awalk_app_isoI) qed lemma euler_trail_app_isoI: assumes t: "euler_trail u p v" and hom: "digraph_isomorphism hom" shows "pre_digraph.euler_trail (app_iso hom G) (iso_verts hom u) (map (iso_arcs hom) p) (iso_verts hom v)" proof - from t have "awalk u p v" by (auto simp: euler_trail_def trail_def) with assms show ?thesis by (simp add: pre_digraph.euler_trail_def trail_app_isoI awalk_verts_app_iso_eq) qed end context fin_digraph begin (* XXX: We can get rid of "u ∈ verts G" "v ∈ verts G" here and in @{thm open_euler_infinite_label} *) theorem open_euler1: assumes "connected G" assumes "u ∈ verts G" "v ∈ verts G" assumes "⋀w. ⟦w ∈ verts G; u ≠ w; v ≠ w⟧ ⟹ in_degree G w = out_degree G w" assumes "in_degree G u + 1 = out_degree G u" assumes "out_degree G v + 1 = in_degree G v" shows "∃p. euler_trail u p v" proof - obtain f and n :: nat where "f ` arcs G = {i. i < n}" and i: "inj_on f (arcs G)" by atomize_elim (rule finite_imp_inj_to_nat_seg, auto) define iso_f where "iso_f = ⦇ iso_verts = id, iso_arcs = (λa. (tail G a, f a, head G a)), head = snd o snd, tail = fst ⦈" have [simp]: "iso_verts iso_f = id" "iso_head iso_f = snd o snd" "iso_tail iso_f = fst" unfolding iso_f_def by auto have di_iso_f: "digraph_isomorphism iso_f" unfolding digraph_isomorphism_def iso_f_def by (auto intro: inj_onI wf_digraph dest: inj_onD[OF i]) let ?iso_g = "inv_iso iso_f" have [simp]: "⋀u. u ∈ verts G ⟹ iso_verts ?iso_g u = u" by (auto simp: inv_iso_def fun_eq_iff the_inv_into_f_eq) let ?H = "app_iso iso_f G" interpret H: fin_digraph ?H using di_iso_f .. have "∃p. H.euler_trail u p v" using di_iso_f assms i by (intro open_euler_infinite_label) (auto simp: connectedI_app_iso app_iso_eq) then obtain p where Het: "H.euler_trail u p v" by blast have "pre_digraph.euler_trail (app_iso ?iso_g ?H) (iso_verts ?iso_g u) (map (iso_arcs ?iso_g) p) (iso_verts ?iso_g v)" using Het by (intro H.euler_trail_app_isoI digraph_isomorphism_invI di_iso_f) then show ?thesis using di_iso_f ‹u ∈ _› ‹v ∈ _› by simp rule qed theorem open_euler2: assumes et: "euler_trail u p v" and "u ≠ v" shows "connected G ∧ (∀w ∈ verts G. u ≠ w ⟶ v ≠ w ⟶ in_degree G w = out_degree G w) ∧ in_degree G u + 1 = out_degree G u ∧ out_degree G v + 1 = in_degree G v" proof - from et have *: "trail u p v" "u ∈ verts G" "v ∈ verts G" by (auto simp: euler_trail_def trail_def awalk_hd_in_verts) from et have [simp]: "⋀u. card (in_arcs G u ∩ set p) = in_degree G u" "⋀u. card (out_arcs G u ∩ set p) = out_degree G u" by (auto simp: in_degree_def out_degree_def euler_trail_def intro: arg_cong[where f=card]) from assms * show ?thesis by (auto simp: arc_set_balance_def elim: trail_arc_balanceE intro: euler_imp_connected) qed corollary open_euler: "(∃u p v. euler_trail u p v ∧ u ≠ v) ⟷ connected G ∧ (∃u v. u ∈ verts G ∧ v ∈ verts G ∧ (∀w ∈ verts G. u ≠ w ⟶ v ≠ w ⟶ in_degree G w = out_degree G w) ∧ in_degree G u + 1 = out_degree G u ∧ out_degree G v + 1 = in_degree G v)" (is "?L ⟷ ?R") proof assume ?L then obtain u p v where *: "euler_trail u p v" "u ≠ v" by auto then have "u ∈ verts G" "v ∈ verts G" by (auto simp: euler_trail_def trail_def awalk_hd_in_verts) then show ?R using open_euler2[OF *] by blast next assume ?R then obtain u v where *: "connected G" "u ∈ verts G" "v ∈ verts G" "⋀w. ⟦w ∈ verts G; u ≠ w; v ≠ w⟧ ⟹ in_degree G w = out_degree G w" "in_degree G u + 1 = out_degree G u" "out_degree G v + 1 = in_degree G v" by blast then have "u ≠ v" by auto from * show ?L by (metis open_euler1 ‹u ≠ v›) qed end end