Skip to content

Commit fa9f474

Browse files
committed
feat(Combinatorics/SimpleGraph/Walk): lemmas about the first and last darts/edges (#31416)
1 parent 3ae4a54 commit fa9f474

File tree

4 files changed

+109
-19
lines changed

4 files changed

+109
-19
lines changed

Mathlib/Combinatorics/SimpleGraph/Acyclic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ theorem IsAcyclic.isPath_iff_isChain (hG : G.IsAcyclic) {v w : V} (p : G.Walk v
284284
by_contra hhh
285285
refine hcc.1 s(u', v') ?_ rfl
286286
rw [← tail.cons_tail_eq (by simp [not_nil_iff_lt_length, h'])]
287-
have := IsPath.mk' this |>.eq_snd_of_mem_edges (by simp [head.ne.symm]) (Sym2.eq_swap ▸ hhh)
287+
have := IsPath.mk' this |>.eq_snd_of_mem_edges (Sym2.eq_swap ▸ hhh)
288288
simp [this, snd_takeUntil head.ne]
289289

290290
theorem IsAcyclic.isPath_iff_isTrail (hG : G.IsAcyclic) {v w : V} (p : G.Walk v w) :

Mathlib/Combinatorics/SimpleGraph/Paths.lean

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,15 +398,16 @@ lemma IsPath.getVert_injOn_iff (p : G.Walk u v) : Set.InjOn p.getVert {i | i ≤
398398
(by rwa [getVert_cons _ _ n.add_one_ne_zero, getVert_zero])
399399
omega
400400

401-
theorem IsPath.eq_snd_of_mem_edges {p : G.Walk u v} (hp : p.IsPath) (hnil : ¬p.Nil)
402-
(hmem : s(u, w) ∈ p.edges) : w = p.snd := by
401+
theorem IsPath.eq_snd_of_mem_edges {p : G.Walk u v} (hp : p.IsPath) (hmem : s(u, w) ∈ p.edges) :
402+
w = p.snd := by
403+
have hnil := edges_eq_nil.not.mp <| List.ne_nil_of_mem hmem
403404
rw [← cons_tail_eq _ hnil, edges_cons, List.mem_cons, Sym2.eq, Sym2.rel_iff'] at hmem
404405
have : u ∉ p.tail.support := by induction p <;> simp_all
405406
grind [fst_mem_support_of_mem_edges]
406407

407-
theorem IsPath.eq_penultimate_of_mem_edges {p : G.Walk u v} (hp : p.IsPath) (hnil : ¬p.Nil)
408+
theorem IsPath.eq_penultimate_of_mem_edges {p : G.Walk u v} (hp : p.IsPath)
408409
(hmem : s(v, w) ∈ p.edges) : w = p.penultimate := by
409-
simpa [hnil, hmem] using isPath_reverse_iff p |>.mpr hp |>.eq_snd_of_mem_edges (w := w)
410+
simpa [hmem] using isPath_reverse_iff p |>.mpr hp |>.eq_snd_of_mem_edges (w := w)
410411

411412
/-! ### About cycles -/
412413

Mathlib/Combinatorics/SimpleGraph/Walks/Basic.lean

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,6 @@ theorem map_fst_darts_append {u v : V} (p : G.Walk u v) :
239239
theorem map_fst_darts {u v : V} (p : G.Walk u v) : p.darts.map (·.fst) = p.support.dropLast := by
240240
simpa! using congr_arg List.dropLast (map_fst_darts_append p)
241241

242-
@[simp]
243-
theorem head_darts_fst {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) :
244-
(p.darts.head hp).fst = a := by
245-
cases p
246-
· contradiction
247-
· simp
248-
249-
@[simp]
250-
theorem getLast_darts_snd {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) :
251-
(p.darts.getLast hp).snd = b := by
252-
rw [← List.getLast_map (f := fun x : G.Dart ↦ x.snd) (by simpa)]
253-
simp_rw [p.map_snd_darts, List.getLast_tail, p.getLast_support]
254-
255242
@[simp]
256243
theorem edges_nil {u : V} : (nil : G.Walk u u).edges = [] := rfl
257244

@@ -348,6 +335,14 @@ lemma not_nil_of_ne {p : G.Walk v w} : v ≠ w → ¬ p.Nil := mt Nil.eq
348335
lemma nil_iff_support_eq {p : G.Walk v w} : p.Nil ↔ p.support = [v] := by
349336
cases p <;> simp
350337

338+
@[simp]
339+
lemma darts_eq_nil {p : G.Walk v w} : p.darts = [] ↔ p.Nil := by
340+
cases p <;> simp
341+
342+
@[simp]
343+
lemma edges_eq_nil {p : G.Walk v w} : p.edges = [] ↔ p.Nil := by
344+
cases p <;> simp
345+
351346
lemma nil_iff_length_eq {p : G.Walk v w} : p.Nil ↔ p.length = 0 := by
352347
cases p <;> simp
353348

Mathlib/Combinatorics/SimpleGraph/Walks/Traversal.lean

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ lemma getVert_cons {u v w n} (p : G.Walk v w) (h : G.Adj u v) (hn : n ≠ 0) :
8484
theorem getVert_mem_support {u v : V} (p : G.Walk u v) (i : ℕ) : p.getVert i ∈ p.support := by
8585
induction p generalizing i <;> cases i <;> simp [*]
8686

87+
/-- Use `support_getElem_eq_getVert` to rewrite in the reverse direction. -/
8788
lemma getVert_eq_support_getElem {u v : V} {n : ℕ} (p : G.Walk u v) (h : n ≤ p.length) :
8889
p.getVert n = p.support[n]'(p.length_support ▸ Nat.lt_add_one_of_le h) := by
8990
cases p with
@@ -94,6 +95,11 @@ lemma getVert_eq_support_getElem {u v : V} {n : ℕ} (p : G.Walk u v) (h : n ≤
9495
simp_rw [support_cons, getVert_cons _ _ n.zero_ne_add_one.symm, List.getElem_cons]
9596
exact getVert_eq_support_getElem _ (Nat.sub_le_of_le_add h)
9697

98+
/-- Use `getVert_eq_support_getElem` to rewrite in the reverse direction. -/
99+
lemma support_getElem_eq_getVert {u v : V} {n : ℕ} (p : G.Walk u v) (h) :
100+
p.support[n]'h = p.getVert n :=
101+
(p.getVert_eq_support_getElem <| by grind).symm
102+
97103
lemma getVert_eq_support_getElem? {u v : V} {n : ℕ} (p : G.Walk u v) (h : n ≤ p.length) :
98104
some (p.getVert n) = p.support[n]? := by
99105
rw [getVert_eq_support_getElem p h, ← List.getElem?_eq_getElem]
@@ -122,7 +128,9 @@ theorem darts_getElem_eq_getVert {u v : V} {p : G.Walk u v} (n : ℕ) (h : n < p
122128
ext
123129
· simp only [p.getVert_eq_support_getElem (le_of_lt h)]
124130
by_cases h' : n = 0
125-
· simp [h', List.getElem_zero]
131+
· cases p
132+
· contradiction
133+
· simp [h']
126134
· have := p.isChain_dartAdj_darts.getElem (n - 1) (by grind)
127135
grind [DartAdj, =_ cons_map_snd_darts]
128136
· simp [p.getVert_eq_support_getElem h, ← p.cons_map_snd_darts]
@@ -140,6 +148,16 @@ lemma snd_cons {u v w} (q : G.Walk v w) (hadj : G.Adj u v) :
140148
lemma snd_mem_tail_support {u v : V} {p : G.Walk u v} (h : ¬p.Nil) : p.snd ∈ p.support.tail :=
141149
p.notNilRec (by simp) h
142150

151+
/-- Use `snd_eq_support_getElem_one` to rewrite in the reverse direction. -/
152+
@[simp]
153+
lemma support_getElem_one {p : G.Walk u v} (hp) : p.support[1]'hp = p.snd := by
154+
grind [getVert_eq_support_getElem]
155+
156+
/-- Use `support_getElem_one` to rewrite in the reverse direction. -/
157+
lemma snd_eq_support_getElem_one {p : G.Walk u v} (hnil : ¬p.Nil) :
158+
p.snd = p.support[1]'(by grind [not_nil_iff_lt_length]) :=
159+
support_getElem_one _ |>.symm
160+
143161
/-- The penultimate vertex of a walk, or the only vertex in a nil walk. -/
144162
abbrev penultimate (p : G.Walk u v) : V := p.getVert (p.length - 1)
145163

@@ -164,6 +182,16 @@ lemma adj_penultimate {p : G.Walk v w} (hp : ¬ p.Nil) :
164182
rw [nil_iff_length_eq] at hp
165183
convert adj_getVert_succ _ _ <;> omega
166184

185+
lemma penultimate_mem_dropLast_support {p : G.Walk u v} (h : ¬p.Nil) :
186+
p.penultimate ∈ p.support.dropLast := by
187+
have := adj_penultimate h |>.ne
188+
grind [getVert_mem_support, List.dropLast_concat_getLast, getLast_support]
189+
190+
@[simp]
191+
lemma support_getElem_length_sub_one_eq_penultimate {p : G.Walk u v} :
192+
p.support[p.length - 1] = p.penultimate := by
193+
grind [getVert_eq_support_getElem]
194+
167195
/-- The first dart of a walk. -/
168196
@[simps]
169197
def firstDart (p : G.Walk v w) (hp : ¬ p.Nil) : G.Dart where
@@ -193,6 +221,72 @@ theorem lastDart_eq {p : G.Walk v w} (h₁ : ¬ p.Nil) (h₂ : 0 < p.darts.lengt
193221
simp (disch := grind) [Dart.ext_iff, lastDart_toProd, darts_getElem_eq_getVert,
194222
p.getVert_of_length_le]
195223

224+
/-- Use `firstDart_eq_head_darts` to rewrite in the reverse direction. -/
225+
@[simp]
226+
theorem head_darts_eq_firstDart {p : G.Walk v w} (hnil : p.darts ≠ []) :
227+
p.darts.head hnil = p.firstDart (darts_eq_nil.not.mp hnil) := by
228+
grind [firstDart_eq]
229+
230+
/-- Use `head_darts_eq_firstDart` to rewrite in the reverse direction. -/
231+
theorem firstDart_eq_head_darts {p : G.Walk v w} (hnil : ¬p.Nil) :
232+
p.firstDart hnil = p.darts.head (darts_eq_nil.not.mpr hnil) :=
233+
head_darts_eq_firstDart _ |>.symm
234+
235+
@[deprecated "Use `head_darts_eq_firstDart`" (since := "2025-12-10")]
236+
theorem head_darts_fst {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) :
237+
(p.darts.head hp).fst = a := by
238+
simp
239+
240+
@[simp]
241+
theorem firstDart_mem_darts {p : G.Walk v w} (hnil : ¬p.Nil) : p.firstDart hnil ∈ p.darts :=
242+
p.firstDart_eq_head_darts _ ▸ List.head_mem _
243+
244+
@[simp]
245+
theorem getLast_darts_eq_lastDart {p : G.Walk v w} (hnil : p.darts ≠ []) :
246+
p.darts.getLast hnil = p.lastDart (darts_eq_nil.not.mp hnil) := by
247+
grind [lastDart_eq, not_nil_iff_lt_length]
248+
249+
theorem lastDart_eq_getLast_darts {p : G.Walk v w} (hnil : ¬p.Nil) :
250+
p.lastDart hnil = p.darts.getLast (darts_eq_nil.not.mpr hnil) := by
251+
grind [lastDart_eq, not_nil_iff_lt_length]
252+
253+
@[deprecated "Use `getLast_darts_eq_lastDart`" (since := "2025-12-10")]
254+
theorem getLast_darts_snd {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) :
255+
(p.darts.getLast hp).snd = b := by
256+
simp
257+
258+
@[simp]
259+
theorem lastDart_mem_darts {p : G.Walk v w} (hnil : ¬p.Nil) : p.lastDart hnil ∈ p.darts :=
260+
p.lastDart_eq_getLast_darts _ ▸ List.getLast_mem _
261+
262+
/-- Use `mk_start_snd_eq_head_edges` to rewrite in the reverse direction. -/
263+
@[simp]
264+
theorem head_edges_eq_mk_start_snd {p : G.Walk v w} (hp) : p.edges.head hp = s(v, p.snd) := by
265+
simp [p.edge_firstDart, Walk.edges]
266+
267+
/-- Use `head_edges_eq_mk_start_snd` to rewrite in the reverse direction. -/
268+
theorem mk_start_snd_eq_head_edges {p : G.Walk v w} (hnil : ¬p.Nil) :
269+
s(v, p.snd) = p.edges.head (edges_eq_nil.not.mpr hnil) :=
270+
head_edges_eq_mk_start_snd _ |>.symm
271+
272+
theorem mk_start_snd_mem_edges {p : G.Walk v w} (hnil : ¬p.Nil) : s(v, p.snd) ∈ p.edges :=
273+
p.mk_start_snd_eq_head_edges hnil ▸ List.head_mem _
274+
275+
/-- Use `mk_penultimate_end_eq_getLast_edges` to rewrite in the reverse direction. -/
276+
@[simp]
277+
theorem getLast_edges_eq_mk_penultimate_end {p : G.Walk v w} (hp) :
278+
p.edges.getLast hp = s(p.penultimate, w) := by
279+
simp [p.edge_lastDart, Walk.edges]
280+
281+
/-- Use `getLast_edges_eq_mk_penultimate_end` to rewrite in the reverse direction. -/
282+
theorem mk_penultimate_end_eq_getLast_edges {p : G.Walk v w} (hnil : ¬p.Nil) :
283+
s(p.penultimate, w) = p.edges.getLast (edges_eq_nil.not.mpr hnil) :=
284+
getLast_edges_eq_mk_penultimate_end _ |>.symm
285+
286+
theorem mk_penultimate_end_mem_edges {p : G.Walk v w} (hnil : ¬p.Nil) :
287+
s(p.penultimate, w) ∈ p.edges :=
288+
p.mk_penultimate_end_eq_getLast_edges hnil ▸ List.getLast_mem _
289+
196290
end Walk
197291

198292
end SimpleGraph

0 commit comments

Comments
 (0)