@@ -150,15 +150,18 @@ theorem reverse_isTrail_iff {u v : V} (p : G.Walk u v) : p.reverse.IsTrail ↔ p
150150 convert! h.reverse _
151151 try rw [reverse_reverse]
152152
153+ @[simp]
154+ theorem isTrail_append {u v w : V} (p : G.Walk u v) (q : G.Walk v w) :
155+ (p.append q).IsTrail ↔ p.IsTrail ∧ q.IsTrail ∧ p.edges.Disjoint q.edges := by
156+ simp [Walk.isTrail_def, List.nodup_append']
157+
153158theorem IsTrail.of_append_left {u v w : V} {p : G.Walk u v} {q : G.Walk v w}
154159 (h : (p.append q).IsTrail) : p.IsTrail := by
155- rw [isTrail_def, edges_append, List.nodup_append] at h
156- exact ⟨h.1 ⟩
160+ simp_all
157161
158162theorem IsTrail.of_append_right {u v w : V} {p : G.Walk u v} {q : G.Walk v w}
159163 (h : (p.append q).IsTrail) : q.IsTrail := by
160- rw [isTrail_def, edges_append, List.nodup_append] at h
161- exact ⟨h.2 .1 ⟩
164+ simp_all
162165
163166theorem IsTrail.count_edges_le_one [DecidableEq V] {u v : V} {p : G.Walk u v} (h : p.IsTrail)
164167 (e : Sym2 V) : p.edges.count e ≤ 1 :=
@@ -716,7 +719,97 @@ end Path
716719
717720namespace Walk
718721
719- variable {G} [DecidableEq V] {u u' v v' : V}
722+ variable {G} {u v : V}
723+
724+ theorem IsPath.length_eq_one_of_mem_edges {p : G.Walk u v} (hp : p.IsPath) (h : s(u, v) ∈ p.edges) :
725+ p.length = 1 := by
726+ suffices p.length - 1 = 0 by grind [length_edges]
727+ rw [← hp.getVert_eq_start_iff <| p.length.sub_le 1 ]
728+ exact (hp.eq_penultimate_of_mem_edges <| Sym2.eq_swap ▸ h).symm
729+
730+ theorem IsPath.eq_adj_toWalk_of_mem_edges {p : G.Walk u v} (hp : p.IsPath) (h : s(u, v) ∈ p.edges) :
731+ p = (p.adj_of_mem_edges h).toWalk := by
732+ apply p.ext_getVert_le_length <| by simp [hp.length_eq_one_of_mem_edges h]
733+ intro _ hl
734+ cases Nat.le_one_iff_eq_zero_or_eq_one.mp (hp.length_eq_one_of_mem_edges h ▸ hl) with
735+ | inl hl => simp [hl]
736+ | inr hl =>
737+ rw [hl, getVert_cons_succ, getVert_zero, ← hp.length_eq_one_of_mem_edges h, getVert_length]
738+
739+ theorem IsPath.disjoint_edges_of_disjoint_support {p : G.Walk u v} {q : G.Walk v u} (hp : p.IsPath)
740+ (hd : p.support.tail.Disjoint q.support.tail) (hl : p.length ≠ 1 ) :
741+ p.edges.Disjoint q.edges := by
742+ simp only [List.disjoint_left] at hd ⊢
743+ contrapose! hd
744+ obtain ⟨⟨a, b⟩, hep, heq⟩ := hd
745+ have := p.mem_support_iff.mp <| p.fst_mem_support_of_mem_edges hep
746+ have := p.mem_support_iff.mp <| p.snd_mem_support_of_mem_edges hep
747+ have := q.mem_support_iff.mp <| q.fst_mem_support_of_mem_edges heq
748+ have := q.mem_support_iff.mp <| q.snd_mem_support_of_mem_edges heq
749+ grind [p.adj_of_mem_edges hep |>.ne, length_eq_one_of_mem_edges]
750+
751+ lemma IsPath.isCycle_append {p : G.Walk u v} {q : G.Walk v u} (hp : p.IsPath) (hq : q.IsPath)
752+ (h : p.support.tail.Disjoint q.support.tail) (hn : 1 < p.length ∨ 1 < q.length) :
753+ (p.append q).IsCycle := by
754+ rw [isCycle_def, isTrail_append]
755+ refine ⟨⟨hp.isTrail, hq.isTrail, ?_⟩, ?_, ?_⟩
756+ · grind [IsPath.disjoint_edges_of_disjoint_support, List.Disjoint.symm]
757+ · grind [nil_append_iff, length_eq_zero_iff]
758+ · rw [tail_support_append, List.nodup_append']
759+ exact ⟨hp.support_nodup.tail, hq.support_nodup.tail, h⟩
760+
761+ /--
762+ Given two distinct paths with the same endpoints, we can extract a subwalk from each such that their
763+ concatenation, with one reversed, forms a cycle.
764+ -/
765+ theorem IsPath.exists_isCycle_of_ne {p q : G.Walk u v} (hp : p.IsPath) (hq : q.IsPath)
766+ (h : p ≠ q) :
767+ ∃ (u' v' : V) (p' q' : G.Walk u' v'),
768+ p'.IsSubwalk p ∧ q'.IsSubwalk q ∧ (p'.append q'.reverse).IsCycle := by
769+ induction hs : p.length using Nat.strongRec generalizing u v with | ind s ih =>
770+ by_cases! hw : ∃ w, w ∈ p.support ∧ w ∈ q.support ∧ w ≠ u ∧ w ≠ v
771+ · classical
772+ have ⟨w, hwp, hwq, hwu, hwv⟩ := hw
773+ by_cases! p.takeUntil w hwp ≠ q.takeUntil w hwq
774+ · have := ih _ (hs ▸ length_takeUntil_lt_length hwp hwv) (hp.takeUntil hwp) (hq.takeUntil hwq)
775+ grind [isSubwalk_takeUntil, IsSubwalk.trans]
776+ · have := ih _ (hs ▸ length_dropUntil_lt_length hwp hwu) (hp.dropUntil hwp) (hq.dropUntil hwq)
777+ <| by grind [take_spec]
778+ grind [isSubwalk_dropUntil, IsSubwalk.trans]
779+ · refine ⟨u, v, p, q, p.isSubwalk_rfl, q.isSubwalk_rfl, ?_⟩
780+ refine hp.isCycle_append (isPath_reverse_iff q |>.mpr hq) (fun _ ↦ ?_) ?_
781+ · grind [dropLast_support_concat, IsPath.support_nodup, support_reverse, cons_tail_support]
782+ · grind [length_reverse, eq_of_length_le_one]
783+
784+ open List in
785+ /--
786+ Given two distinct paths, `p` and `q`, with same endpoints, we can extract a cycle whose support
787+ is a sublist of `p.support ++ q.support.reverse.tail`.
788+ -/
789+ theorem IsPath.exists_isCycle_sublist_of_ne {p q : G.Walk u v} (hp : p.IsPath)
790+ (hq : q.IsPath) (h : p ≠ q) :
791+ ∃ w, w ∈ p.support ∧ w ∈ q.support ∧
792+ ∃ c : G.Walk w w, c.IsCycle ∧ c.support <+ (p.support ++ q.support.reverse.tail) := by
793+ have ⟨u', v', p', q', hp', hq', hcyc⟩ := hp.exists_isCycle_of_ne hq h
794+ use u', hp'.support_subset p'.start_mem_support, hq'.support_subset q'.start_mem_support
795+ refine ⟨_, hcyc, ?_⟩
796+ rw [support_append, support_reverse]
797+ refine .append ?_ <| .tail <| .reverse ?_
798+ · exact isSubwalk_iff_support_isInfix.mp hp' |>.sublist
799+ · exact isSubwalk_iff_support_isInfix.mp hq' |>.sublist
800+
801+ /--
802+ Given two distinct paths with same endpoints, we can extract a cycle whose length is less than or
803+ equal to the sum of their lengths.
804+ -/
805+ theorem IsPath.exists_isCycle_length_le_add_of_ne {p q : G.Walk u v} (hp : p.IsPath)
806+ (hq : q.IsPath) (h : p ≠ q) :
807+ ∃ w, w ∈ p.support ∧ w ∈ q.support ∧
808+ ∃ c : G.Walk w w, c.IsCycle ∧ c.length ≤ p.length + q.length := by
809+ obtain ⟨w, hw₁, hw₂, c, hc₁, hc₂⟩ := hp.exists_isCycle_sublist_of_ne hq h
810+ use w, hw₁, hw₂, c, hc₁, by grind [hc₂.length_le]
811+
812+ variable [DecidableEq V] {u' v' : V}
720813
721814/-- Given a walk, produces a walk from it by bypassing subwalks between repeated vertices.
722815The result is a path, as shown in `SimpleGraph.Walk.bypass_isPath`.
0 commit comments