[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Order.Interval.Set.Basic).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem Icc_ofDual {x y : αᵒᵈ} : Icc (ofDual y) (ofDual x) = toDual ⁻¹' Icc x y
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.Interval.Set.Basic.Ico_subset_Ici (L34-L39)
theorem Ico_subset_Ici (h : a₂ ≤ a₁) : Ico a₁ b₁ ⊆ Ici a₂ :=
(Ico_subset_Ico_left h).trans Ico_subset_Ici_self
```
Logical equivalences, such as `Icc_subset_Ici_iff`, are however stated.
-/
```

-- snippet 2
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIio (L57-L58)
instance decidableMemIio [Decidable (x < b)] : Decidable (x ∈ Iio b) := by assumption
```

-- snippet 3
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIic (L60-L61)
instance decidableMemIic [Decidable (x ≤ b)] : Decidable (x ∈ Iic b) := by assumption
```

-- snippet 4
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIoo (L63-L65)
instance decidableMemIoo [Decidable (a < x)] [Decidable (x < b)] : Decidable (x ∈ Ioo a b) :=
instDecidableAnd
```

-- snippet 5
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIco (L66-L68)
instance decidableMemIco [Decidable (a ≤ x)] [Decidable (x < b)] : Decidable (x ∈ Ico a b) :=
instDecidableAnd
```

-- snippet 6
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIcc (L70-L72)
instance decidableMemIcc [Decidable (a ≤ x)] [Decidable (x ≤ b)] : Decidable (x ∈ Icc a b) :=
instDecidableAnd
```

-- snippet 7
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIoc (L74-L76)
instance decidableMemIoc [Decidable (a < x)] [Decidable (x ≤ b)] : Decidable (x ∈ Ioc a b) :=
instDecidableAnd
```

-- snippet 8
```lean
-- Mathlib.Order.Interval.Set.Basic.left_notMem_Ioo (L81-L82)
theorem left_notMem_Ioo : a ∉ Ioo a b := by simp
```

-- snippet 9
```lean
-- Mathlib.Order.Interval.Set.Basic.left_notMem_Ioc (L84-L85)
theorem left_notMem_Ioc : a ∉ Ioc a b := by simp
```

-- snippet 10
```lean
-- Mathlib.Order.Interval.Set.Basic.left_mem_Ioo (L87-L88)
theorem left_mem_Ioo : a ∈ Ioo a b ↔ False := by simp
```

-- snippet 11
```lean
-- Mathlib.Order.Interval.Set.Basic.left_mem_Ioc (L90-L91)
theorem left_mem_Ioc : a ∈ Ioc a b ↔ False := by simp
```

-- snippet 12
```lean
-- Mathlib.Order.Interval.Set.Basic.right_mem_Ioo (L99-L100)
theorem right_mem_Ioo : b ∈ Ioo a b ↔ False := by simp
```

-- snippet 13
```lean
-- Mathlib.Order.Interval.Set.Basic.right_mem_Ico (L102-L103)
theorem right_mem_Ico : b ∈ Ico a b ↔ False := by simp
```

-- snippet 14
```lean
-- Mathlib.Order.Interval.Set.Basic.Iio_toDual (L108-L110)
theorem Iio_toDual : Iio (toDual a) = ofDual ⁻¹' Ioi a :=
rfl
```

-- snippet 15
```lean
-- Mathlib.Order.Interval.Set.Basic.Iic_toDual (L112-L114)
theorem Iic_toDual : Iic (toDual a) = ofDual ⁻¹' Ici a :=
rfl
```

-- snippet 16
```lean
-- Mathlib.Order.Interval.Basic.mem_def (L127-L129)
theorem mem_def : a ∈ s ↔ s.fst ≤ a ∧ a ≤ s.snd :=
Iff.rfl
```

-- snippet 17
```lean
-- Mathlib.Order.Interval.Basic.dual (L92-L95)
def dual : NonemptyInterval α ≃ NonemptyInterval αᵒᵈ where
  toFun s := ⟨s.toProd.swap, s.fst_le_snd⟩
invFun s := ⟨s.toProd.swap, s.fst_le_snd⟩
```

-- snippet 18
```lean
-- Mathlib.Order.Interval.Basic.map_map (L167-L170)
theorem map_map (g : β →o γ) (f : α →o β) (a : NonemptyInterval α) :
    (a.map f).map g = a.map (g.comp f) :=
rfl
```

-- snippet 19
```lean
-- Mathlib.Order.Interval.Basic.le_def (L78-L80)
theorem le_def : s ≤ t ↔ t.fst ≤ s.fst ∧ s.snd ≤ t.snd :=
Iff.rfl
```

-- snippet 20
```lean
-- Mathlib.Order.Interval.Basic.mem_pure_self (L138-L140)
theorem mem_pure_self (a : α) : a ∈ pure a :=
⟨le_rfl, le_rfl⟩
```

-- snippet 21
```lean
-- Mathlib.Order.Interval.Basic.dual_pure (L145-L147)
theorem dual_pure (a : α) : dual (pure a) = pure (toDual a) :=
rfl
```

-- snippet 22
```lean
-- Mathlib.Order.Interval.Basic.mem_mk (L124-L126)
theorem mem_mk {hx : x.1 ≤ x.2} : a ∈ mk x hx ↔ x.1 ≤ a ∧ a ≤ x.2 :=
Iff.rfl
```

-- snippet 23
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_strictMono (L115-L116)
theorem toDualProd_strictMono : StrictMono (toDualProd : _ → αᵒᵈ × α) := fun _ _ => id
```

-- snippet 24
```lean
-- Mathlib.Order.Interval.Basic.pure (L135-L137)
def pure (a : α) : NonemptyInterval α :=
⟨⟨a, a⟩, le_rfl⟩
```

-- snippet 25
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_injective (L63-L65)
theorem toDualProd_injective : Injective (toDualProd : NonemptyInterval α → αᵒᵈ × α) :=
toProd_injective
```

-- snippet 26
```lean
-- Mathlib.Order.Interval.Basic.map₂ (L178-L181)
def map₂ (f : α → β → γ) (h₀ : ∀ b, Monotone fun a => f a b) (h₁ : ∀ a, Monotone (f a)) :
    NonemptyInterval α → NonemptyInterval β → NonemptyInterval γ := fun s t =>
⟨(f s.fst t.fst, f s.snd t.snd), (h₀ _ s.fst_le_snd).trans <| h₁ _ t.fst_le_snd⟩
```

-- snippet 27
```lean
-- Mathlib.Order.Interval.Basic.toDualProd (L56-L58)
def toDualProd : NonemptyInterval α → αᵒᵈ × α :=
toProd
```

-- snippet 28
```lean
-- Mathlib.Order.Interval.Basic.fst_dual (L97-L99)
theorem fst_dual (s : NonemptyInterval α) : s.dual.fst = toDual s.snd :=
rfl
```

-- snippet 29
```lean
-- Mathlib.Order.Interval.Basic.toDualProdHom (L86-L91)
def toDualProdHom : NonemptyInterval α ↪o αᵒᵈ × α where
  toFun := toDualProd
inj' := toDualProd_injective
  map_rel_iff' := Iff.rfl

/-- Turn an interval into an interval in the dual order. -/
```

-- snippet 30
```lean
-- Mathlib.Order.Interval.Basic.instCanLift (L51-L55)
instance instCanLift :
    CanLift (α × α) (NonemptyInterval α) NonemptyInterval.toProd (fun x ↦ x.1 ≤ x.2) where
  prf x hx := ⟨⟨x, hx⟩, rfl⟩
/-- The injection that induces the order on intervals. -/
```

-- snippet 31
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_apply (L60-L62)
theorem toDualProd_apply (s : NonemptyInterval α) : s.toDualProd = (toDual s.fst, s.snd) :=
rfl
```

-- snippet 32
```lean
-- Mathlib.Order.Interval.Basic.map (L159-L161)
def map (f : α →o β) (a : NonemptyInterval α) : NonemptyInterval β :=
⟨a.toProd.map f f, f.mono a.fst_le_snd⟩
```

-- snippet 33
```lean
-- Mathlib.Order.Interval.Basic.coe_nonempty (L130-L133)
theorem coe_nonempty (s : NonemptyInterval α) : (s : Set α).Nonempty :=
nonempty_Icc.2 s.fst_le_snd

/-- `{a}` as an interval. -/
```

-- snippet 34
```lean
-- Mathlib.Order.Interval.Basic.snd_dual (L101-L109)
theorem snd_dual (s : NonemptyInterval α) : s.dual.snd = toDual s.fst :=
rfl

end LE

section Preorder

variable [Preorder α] [Preorder β] [Preorder γ] {s : NonemptyInterval α} {x : α × α} {a : α}
```

-- snippet 35
```lean
-- Mathlib.Order.Interval.Basic.le (L75-L77)
instance le : LE (NonemptyInterval α) :=
⟨fun s t => t.fst ≤ s.fst ∧ s.snd ≤ t.snd⟩
```

-- snippet 36
```lean
-- Mathlib.Order.Interval.Basic.map_pure (L163-L165)
theorem map_pure (f : α →o β) (a : α) : (pure a).map f = pure (f a) :=
rfl
```

-- snippet 37
```lean
-- Mathlib.Order.Interval.Basic.dual_map (L172-L176)
theorem dual_map (f : α →o β) (a : NonemptyInterval α) :
    dual (a.map f) = a.dual.map f.dual :=
rfl

/-- Binary pushforward of nonempty intervals. -/
```

-- snippet 38
```lean
-- Mathlib.Order.Interval.Basic.toProd_injective (L46-L50)
theorem toProd_injective : Injective (toProd : NonemptyInterval α → α × α) :=
fun s t h => by cases s; cases t; congr

/-- Allow lifting a pair `(a, b)` with `a ≤ b` to `NonemptyInterval`
in the `lift` tactic. -/
```

-- snippet 39
```lean
-- Mathlib.Order.Interval.Basic.pure_injective (L141-L143)
theorem pure_injective : Injective (pure : α → NonemptyInterval α) := fun _ _ =>
congr_arg <| Prod.fst ∘ toProd
```

-- snippet 40
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_mono (L113-L114)
theorem toDualProd_mono : Monotone (toDualProd : _ → αᵒᵈ × α) := fun _ _ => id
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Order.Interval.Set.Basic).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem Icc_ofDual {x y : αᵒᵈ} : Icc (ofDual y) (ofDual x) = toDual ⁻¹' Icc x y
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.Interval.Set.Basic.Ico_subset_Ici (L34-L39)
theorem Ico_subset_Ici (h : a₂ ≤ a₁) : Ico a₁ b₁ ⊆ Ici a₂ :=
(Ico_subset_Ico_left h).trans Ico_subset_Ici_self
```
Logical equivalences, such as `Icc_subset_Ici_iff`, are however stated.
-/
```

-- snippet 2
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIio (L57-L58)
instance decidableMemIio [Decidable (x < b)] : Decidable (x ∈ Iio b) := by assumption
```

-- snippet 3
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIic (L60-L61)
instance decidableMemIic [Decidable (x ≤ b)] : Decidable (x ∈ Iic b) := by assumption
```

-- snippet 4
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIoo (L63-L65)
instance decidableMemIoo [Decidable (a < x)] [Decidable (x < b)] : Decidable (x ∈ Ioo a b) :=
instDecidableAnd
```

-- snippet 5
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIco (L66-L68)
instance decidableMemIco [Decidable (a ≤ x)] [Decidable (x < b)] : Decidable (x ∈ Ico a b) :=
instDecidableAnd
```

-- snippet 6
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIcc (L70-L72)
instance decidableMemIcc [Decidable (a ≤ x)] [Decidable (x ≤ b)] : Decidable (x ∈ Icc a b) :=
instDecidableAnd
```

-- snippet 7
```lean
-- Mathlib.Order.Interval.Set.Basic.decidableMemIoc (L74-L76)
instance decidableMemIoc [Decidable (a < x)] [Decidable (x ≤ b)] : Decidable (x ∈ Ioc a b) :=
instDecidableAnd
```

-- snippet 8
```lean
-- Mathlib.Order.Interval.Set.Basic.left_notMem_Ioo (L81-L82)
theorem left_notMem_Ioo : a ∉ Ioo a b := by simp
```

-- snippet 9
```lean
-- Mathlib.Order.Interval.Set.Basic.left_notMem_Ioc (L84-L85)
theorem left_notMem_Ioc : a ∉ Ioc a b := by simp
```

-- snippet 10
```lean
-- Mathlib.Order.Interval.Set.Basic.left_mem_Ioo (L87-L88)
theorem left_mem_Ioo : a ∈ Ioo a b ↔ False := by simp
```

-- snippet 11
```lean
-- Mathlib.Order.Interval.Set.Basic.left_mem_Ioc (L90-L91)
theorem left_mem_Ioc : a ∈ Ioc a b ↔ False := by simp
```

-- snippet 12
```lean
-- Mathlib.Order.Interval.Set.Basic.right_mem_Ioo (L99-L100)
theorem right_mem_Ioo : b ∈ Ioo a b ↔ False := by simp
```

-- snippet 13
```lean
-- Mathlib.Order.Interval.Set.Basic.right_mem_Ico (L102-L103)
theorem right_mem_Ico : b ∈ Ico a b ↔ False := by simp
```

-- snippet 14
```lean
-- Mathlib.Order.Interval.Set.Basic.Iio_toDual (L108-L110)
theorem Iio_toDual : Iio (toDual a) = ofDual ⁻¹' Ioi a :=
rfl
```

-- snippet 15
```lean
-- Mathlib.Order.Interval.Set.Basic.Iic_toDual (L112-L114)
theorem Iic_toDual : Iic (toDual a) = ofDual ⁻¹' Ici a :=
rfl
```

-- snippet 16
```lean
-- Mathlib.Order.Interval.Basic.mem_def (L127-L129)
theorem mem_def : a ∈ s ↔ s.fst ≤ a ∧ a ≤ s.snd :=
Iff.rfl
```

-- snippet 17
```lean
-- Mathlib.Order.Interval.Basic.dual (L92-L95)
def dual : NonemptyInterval α ≃ NonemptyInterval αᵒᵈ where
  toFun s := ⟨s.toProd.swap, s.fst_le_snd⟩
invFun s := ⟨s.toProd.swap, s.fst_le_snd⟩
```

-- snippet 18
```lean
-- Mathlib.Order.Interval.Basic.map_map (L167-L170)
theorem map_map (g : β →o γ) (f : α →o β) (a : NonemptyInterval α) :
    (a.map f).map g = a.map (g.comp f) :=
rfl
```

-- snippet 19
```lean
-- Mathlib.Order.Interval.Basic.le_def (L78-L80)
theorem le_def : s ≤ t ↔ t.fst ≤ s.fst ∧ s.snd ≤ t.snd :=
Iff.rfl
```

-- snippet 20
```lean
-- Mathlib.Order.Interval.Basic.mem_pure_self (L138-L140)
theorem mem_pure_self (a : α) : a ∈ pure a :=
⟨le_rfl, le_rfl⟩
```

-- snippet 21
```lean
-- Mathlib.Order.Interval.Basic.dual_pure (L145-L147)
theorem dual_pure (a : α) : dual (pure a) = pure (toDual a) :=
rfl
```

-- snippet 22
```lean
-- Mathlib.Order.Interval.Basic.mem_mk (L124-L126)
theorem mem_mk {hx : x.1 ≤ x.2} : a ∈ mk x hx ↔ x.1 ≤ a ∧ a ≤ x.2 :=
Iff.rfl
```

-- snippet 23
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_strictMono (L115-L116)
theorem toDualProd_strictMono : StrictMono (toDualProd : _ → αᵒᵈ × α) := fun _ _ => id
```

-- snippet 24
```lean
-- Mathlib.Order.Interval.Basic.pure (L135-L137)
def pure (a : α) : NonemptyInterval α :=
⟨⟨a, a⟩, le_rfl⟩
```

-- snippet 25
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_injective (L63-L65)
theorem toDualProd_injective : Injective (toDualProd : NonemptyInterval α → αᵒᵈ × α) :=
toProd_injective
```

-- snippet 26
```lean
-- Mathlib.Order.Interval.Basic.map₂ (L178-L181)
def map₂ (f : α → β → γ) (h₀ : ∀ b, Monotone fun a => f a b) (h₁ : ∀ a, Monotone (f a)) :
    NonemptyInterval α → NonemptyInterval β → NonemptyInterval γ := fun s t =>
⟨(f s.fst t.fst, f s.snd t.snd), (h₀ _ s.fst_le_snd).trans <| h₁ _ t.fst_le_snd⟩
```

-- snippet 27
```lean
-- Mathlib.Order.Interval.Basic.toDualProd (L56-L58)
def toDualProd : NonemptyInterval α → αᵒᵈ × α :=
toProd
```

-- snippet 28
```lean
-- Mathlib.Order.Interval.Basic.fst_dual (L97-L99)
theorem fst_dual (s : NonemptyInterval α) : s.dual.fst = toDual s.snd :=
rfl
```

-- snippet 29
```lean
-- Mathlib.Order.Interval.Basic.toDualProdHom (L86-L91)
def toDualProdHom : NonemptyInterval α ↪o αᵒᵈ × α where
  toFun := toDualProd
inj' := toDualProd_injective
  map_rel_iff' := Iff.rfl

/-- Turn an interval into an interval in the dual order. -/
```

-- snippet 30
```lean
-- Mathlib.Order.Interval.Basic.instCanLift (L51-L55)
instance instCanLift :
    CanLift (α × α) (NonemptyInterval α) NonemptyInterval.toProd (fun x ↦ x.1 ≤ x.2) where
  prf x hx := ⟨⟨x, hx⟩, rfl⟩
/-- The injection that induces the order on intervals. -/
```

-- snippet 31
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_apply (L60-L62)
theorem toDualProd_apply (s : NonemptyInterval α) : s.toDualProd = (toDual s.fst, s.snd) :=
rfl
```

-- snippet 32
```lean
-- Mathlib.Order.Interval.Basic.map (L159-L161)
def map (f : α →o β) (a : NonemptyInterval α) : NonemptyInterval β :=
⟨a.toProd.map f f, f.mono a.fst_le_snd⟩
```

-- snippet 33
```lean
-- Mathlib.Order.Interval.Basic.coe_nonempty (L130-L133)
theorem coe_nonempty (s : NonemptyInterval α) : (s : Set α).Nonempty :=
nonempty_Icc.2 s.fst_le_snd

/-- `{a}` as an interval. -/
```

-- snippet 34
```lean
-- Mathlib.Order.Interval.Basic.snd_dual (L101-L109)
theorem snd_dual (s : NonemptyInterval α) : s.dual.snd = toDual s.fst :=
rfl

end LE

section Preorder

variable [Preorder α] [Preorder β] [Preorder γ] {s : NonemptyInterval α} {x : α × α} {a : α}
```

-- snippet 35
```lean
-- Mathlib.Order.Interval.Basic.le (L75-L77)
instance le : LE (NonemptyInterval α) :=
⟨fun s t => t.fst ≤ s.fst ∧ s.snd ≤ t.snd⟩
```

-- snippet 36
```lean
-- Mathlib.Order.Interval.Basic.map_pure (L163-L165)
theorem map_pure (f : α →o β) (a : α) : (pure a).map f = pure (f a) :=
rfl
```

-- snippet 37
```lean
-- Mathlib.Order.Interval.Basic.dual_map (L172-L176)
theorem dual_map (f : α →o β) (a : NonemptyInterval α) :
    dual (a.map f) = a.dual.map f.dual :=
rfl

/-- Binary pushforward of nonempty intervals. -/
```

-- snippet 38
```lean
-- Mathlib.Order.Interval.Basic.toProd_injective (L46-L50)
theorem toProd_injective : Injective (toProd : NonemptyInterval α → α × α) :=
fun s t h => by cases s; cases t; congr

/-- Allow lifting a pair `(a, b)` with `a ≤ b` to `NonemptyInterval`
in the `lift` tactic. -/
```

-- snippet 39
```lean
-- Mathlib.Order.Interval.Basic.pure_injective (L141-L143)
theorem pure_injective : Injective (pure : α → NonemptyInterval α) := fun _ _ =>
congr_arg <| Prod.fst ∘ toProd
```

-- snippet 40
```lean
-- Mathlib.Order.Interval.Basic.toDualProd_mono (L113-L114)
theorem toDualProd_mono : Monotone (toDualProd : _ → αᵒᵈ × α) := fun _ _ => id
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Combinatorics.SimpleGraph.Walks.Operations).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem nodup_tail_support_reverse {u : V} {p : G.Walk u u} :
    p.reverse.support.tail.Nodup ↔ p.support.tail.Nodup
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_rfl_rfl (L52-L53)
theorem copy_rfl_rfl {u v} (p : G.Walk u v) : p.copy rfl rfl = p := rfl
```

-- snippet 2
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_copy (L55-L60)
theorem copy_copy {u v u' v' u'' v''} (p : G.Walk u v)
    (hu : u = u') (hv : v = v') (hu' : u' = u'') (hv' : v' = v'') :
    (p.copy hu hv).copy hu' hv' = p.copy (hu.trans hu') (hv.trans hv') := by
subst_vars
  rfl
```

-- snippet 3
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_nil (L62-L65)
theorem copy_nil {u u'} (hu : u = u') : (Walk.nil : G.Walk u u).copy hu hu = nil := by
subst_vars
  rfl
```

-- snippet 4
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_cons (L66-L70)
theorem copy_cons {u v w u' w'} (h : G.Adj u v) (p : G.Walk v w) (hu : u = u') (hw : w = w') :
    (Walk.cons h p).copy hu hw = Walk.cons (hu ▸ h) (p.copy rfl hw) := by
subst_vars
  rfl
```

-- snippet 5
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_copy (L72-L77)
theorem cons_copy {u v w v' w'} (h : G.Adj u v) (p : G.Walk v' w') (hv : v' = v) (hw : w' = w) :
    cons h (p.copy hv hw) = (Walk.cons (hv ▸ h) p).copy rfl hw := by
subst_vars
  rfl

/-- The concatenation of two compatible walks. -/
```

-- snippet 6
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append (L79-L84)
def append {u v w : V} : G.Walk u v → G.Walk v w → G.Walk u w
  | nil, q => q
  | cons h p, q => cons h (p.append q)

/-- The reversed version of `SimpleGraph.Walk.cons`, concatenating an edge to
the end of a walk. -/
```

-- snippet 7
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat (L85-L86)
def concat {u v w : V} (p : G.Walk u v) (h : G.Adj v w) : G.Walk u w := p.append (cons h nil)
```

-- snippet 8
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat_eq_append (L87-L95)
theorem concat_eq_append {u v w : V} (p : G.Walk u v) (h : G.Adj v w) :
    p.concat h = p.append (cons h nil) := rfl
/-- The concatenation of the reverse of the first walk with the second walk. -/
protected def reverseAux {u v w : V} : G.Walk u v → G.Walk u w → G.Walk v w
  | nil, q => q
  | cons h p, q => Walk.reverseAux p (cons (G.symm h) q)

/-- The walk in reverse. -/
```

-- snippet 9
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.reverse (L97-L98)
def reverse {u v : V} (w : G.Walk u v) : G.Walk v u := w.reverseAux nil
```

-- snippet 10
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_append (L100-L102)
theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w x) :
    (cons h p).append q = cons h (p.append q) := rfl
```

-- snippet 11
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_nil_append (L104-L106)
theorem cons_nil_append {u v w : V} (h : G.Adj u v) (p : G.Walk v w) :
    (cons h nil).append p = cons h p := rfl
```

-- snippet 12
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.nil_append (L108-L110)
theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
rfl
```

-- snippet 13
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_nil (L112-L114)
theorem append_nil {u v : V} (p : G.Walk u v) : p.append nil = p := by
induction p <;> simp [*]
```

-- snippet 14
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_assoc (L115-L118)
theorem append_assoc {u v w x : V} (p : G.Walk u v) (q : G.Walk v w) (r : G.Walk w x) :
    p.append (q.append r) = (p.append q).append r := by
induction p <;> simp [*]
```

-- snippet 15
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_copy_copy (L120-L125)
theorem append_copy_copy {u v w u' v' w'} (p : G.Walk u v) (q : G.Walk v w)
    (hu : u = u') (hv : v = v') (hw : w = w') :
    (p.copy hu hv).append (q.copy hv hw) = (p.append q).copy hu hw := by
subst_vars
  rfl
```

-- snippet 16
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_add_edge_iff_of_not_reachable (L374-L379)
theorem isAcyclic_add_edge_iff_of_not_reachable (x y : V) (hxy : ¬ G.Reachable x y) :
    (G ⊔ fromEdgeSet {s(x, y)}).IsAcyclic ↔ IsAcyclic G :=
⟨.anti le_sup_left, .isAcyclic_sup_fromEdgeSet_of_not_reachable hxy⟩

/-- Adding an edge results in an acyclic graph iff the original graph was acyclic and
the edge connects vertices that previously had no path between them. -/
```

-- snippet 17
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_reachable_eq (L413-L427)
theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (hF : F.IsAcyclic) :
    Maximal (fun F ↦ F ≤ G ∧ F.IsAcyclic) F ↔ F.Reachable = G.Reachable := by
refine ⟨reachable_eq_of_maximal_isAcyclic F, fun h ↦ ?_⟩
  by_contra
  have ⟨H, hFH, hHG, hH⟩ := exists_gt_of_not_maximal ⟨hle, hF⟩ this
  have ⟨e, heH, heF⟩ := Set.exists_of_ssubset <| edgeSet_strict_mono hFH
  have h_bridge : (F ⊔ fromEdgeSet {e}).IsBridge e := by
    refine isAcyclic_iff_forall_edge_isBridge.mp ?_ <| by simp [H.not_isDiag_of_mem_edgeSet heH]
    exact hH.anti <| sup_le_iff.mpr ⟨hFH.le, H.fromEdgeSet_le.mpr <| by grind⟩
  have : (F ⊔ fromEdgeSet {e}) \ fromEdgeSet {e} = F := by simpa using heF
  cases e
  rw [isBridge_iff, this, h] at h_bridge
  exact h_bridge.right <| hHG heH |>.reachable

/-- A subgraph of a connected graph is maximal acyclic iff it is a tree. -/
```

-- snippet 18
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Subgraph (L151-L153)
lemma Subgraph.isAcyclic_coe_bot (G : SimpleGraph V) : (⊥ : G.Subgraph).coe.IsAcyclic :=
@IsAcyclic.of_subsingleton _ (Set.isEmpty_coe_sort.mpr rfl).instSubsingleton _
```

-- snippet 19
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Connected (L428-L436)
theorem Connected.maximal_le_isAcyclic_iff_isTree {T : SimpleGraph V} (hG : G.Connected)
    (hT : T ≤ G) : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) T ↔ T.IsTree := by
have := hG.nonempty
  refine ⟨fun h ↦ ⟨⟨fun u v ↦ ?_⟩, h.1.2⟩, fun hT' ↦ ?_⟩
  · exact G.reachable_eq_of_maximal_isAcyclic T h ▸ hG.preconnected u v
  · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.isAcyclic,
      T.preconnected_iff_reachable_eq_top.mp hT'.preconnected,
      G.preconnected_iff_reachable_eq_top.mp hG.preconnected]
```

-- snippet 20
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_connected_and_card (L486-L499)
lemma isTree_iff_connected_and_card [Finite V] :
    G.IsTree ↔ G.Connected ∧ Nat.card G.edgeSet + 1 = Nat.card V := by
have := Fintype.ofFinite V
  classical
  refine ⟨fun h ↦ ⟨h.connected, by simpa [edgeFinset] using h.card_edgeFinset⟩,
    fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩⟩
  simp_rw [isAcyclic_iff_forall_adj_isBridge]
  refine fun x y h ↦ by_contra fun hbr ↦
    (h₁.connected_delete_edge_of_not_isBridge hbr).card_vert_le_card_edgeSet_add_one.not_gt ?_
  rw [Nat.card_eq_fintype_card, ← edgeFinset_card, ← h₂, Nat.card_eq_fintype_card,
    ← edgeFinset_card, add_lt_add_iff_right]
  exact Finset.card_lt_card <| by simpa [deleteEdges, edgeFinset]

/-- The minimum degree of all vertices in a nontrivial tree is one. -/
```

-- snippet 21
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sSup_of_isAcyclic_directedOn (L118-L126)
lemma isAcyclic_sSup_of_isAcyclic_directedOn (Hs : Set <| SimpleGraph V)
    (h_acyc : ∀ H ∈ Hs, H.IsAcyclic) (h_dir : DirectedOn (· ≤ ·) Hs) : IsAcyclic (sSup Hs) := by
rcases Hs.eq_empty_or_nonempty with rfl | hnemp
  · simp
  · intro u p hp
    obtain ⟨H, hH, hpH⟩ := p.exists_mem_contains_edges_of_directed Hs hnemp h_dir
    exact h_acyc H hH (p.transfer H hpH) <| Walk.IsCycle.transfer hp hpH

/-- Every acyclic subgraph `H ≤ G` is contained in a maximal such subgraph. -/
```

-- snippet 22
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_existsUnique_path (L248-L269)
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
classical
  rw [isTree_iff, isAcyclic_iff_path_unique]
  constructor
  · rintro ⟨hc, hu⟩
    refine ⟨hc.nonempty, ?_⟩
    intro v w
    let q := (hc v w).some.toPath
    use q
    simp only [true_and, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    refine ⟨Connected.mk ?_, ?_⟩
    · intro v w
      obtain ⟨p, _⟩ := h v w
      exact p.reachable
    · rintro v w ⟨p, hp⟩ ⟨q, hq⟩
      simp only [ExistsUnique.unique (h v w) hp hq]
```

-- snippet 23
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_path_unique (L225-L227)
theorem isAcyclic_iff_path_unique : G.IsAcyclic ↔ ∀ ⦃v w : V⦄ (p q : G.Path v w), p = q :=
⟨IsAcyclic.path_unique, isAcyclic_of_path_unique⟩
```

-- snippet 24
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_of_path_unique (L214-L224)
theorem isAcyclic_of_path_unique (h : ∀ (v w : V) (p q : G.Path v w), p = q) : G.IsAcyclic := by
intro v c hc
  simp only [Walk.isCycle_def, Ne] at hc
  cases c with
  | nil => cases hc.2.1 rfl
  | cons ha c' =>
    simp only [Walk.isTrail_cons, Walk.support_cons, List.tail_cons] at hc
    specialize h _ _ ⟨c', by simp only [Walk.isPath_def, hc.2]⟩ (Path.singleton ha.symm)
    rw [Path.singleton, Subtype.mk.injEq] at h
    simp [h] at hc
```

-- snippet 25
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic (L450-L456)
theorem exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic {H : SimpleGraph V} (hH_le : H ≤ G)
    (hH_isAcyclic : H.IsAcyclic) :
    ∃ F : SimpleGraph V, H ≤ F ∧ F ≤ G ∧ F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_maximal_isAcyclic_of_le_isAcyclic hH_le hH_isAcyclic
  grind [maximal_isAcyclic_iff_reachable_eq, Maximal]

/-- Every graph has a spanning forest. -/
```

-- snippet 26
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_maximal_isAcyclic_of_le_isAcyclic (L127-L135)
theorem exists_maximal_isAcyclic_of_le_isAcyclic
    {H : SimpleGraph V} (hHG : H ≤ G) (hH : H.IsAcyclic) :
    ∃ H' : SimpleGraph V, H ≤ H' ∧ Maximal (fun H => H ≤ G ∧ H.IsAcyclic) H' := by
refine zorn_le_nonempty₀ {H | H ≤ G ∧ H.IsAcyclic} (fun c hcs hc y hy ↦ ?_) _ ⟨hHG, hH⟩
  refine ⟨sSup c, ⟨?_, ?_⟩, fun _ ↦ le_sSup⟩
  · grind [sSup_le_iff]
  · exact isAcyclic_sSup_of_isAcyclic_directedOn c (by grind) hc.directedOn

/-- A connected component of an acyclic graph is a tree. -/
```

-- snippet 27
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_isTree (L438-L443)
theorem maximal_isAcyclic_iff_isTree [Nonempty V] {T : SimpleGraph V} :
    Maximal IsAcyclic T ↔ T.IsTree := by
simp [← connected_top.maximal_le_isAcyclic_iff_isTree le_top]

/-- A maximally acyclic graph is a tree. This is similar to `maximal_isAcyclic_iff_isTree` except
with `Nonempty V` as part of the iff rather than an assumption. -/
```

-- snippet 28
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Iso (L80-L83)
lemma Iso.isAcyclic_iff (f : G ≃g G') : G.IsAcyclic ↔ G'.IsAcyclic :=
⟨fun h ↦ h.embedding f.symm, fun h ↦ h.embedding f⟩

/-- Isomorphic graphs are trees together. -/
```

-- snippet 29
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_pairwise_not_isEdgeReachable_two (L650-L658)
lemma isAcyclic_iff_pairwise_not_isEdgeReachable_two :
    G.IsAcyclic ↔ Pairwise (¬G.IsEdgeReachable 2 · ·) := by
refine ⟨fun h _ _ hne he ↦ ?_, fun h ↦ ?_⟩
  · obtain ⟨w, hw⟩ := exists_isCycle_of_two_le_isEdgeReachable hne le_rfl he
    exact h w hw
  · refine isAcyclic_iff_forall_adj_isBridge.mpr fun _ _ hadj ↦ ?_
    exact isBridge_iff_adj_and_not_isEdgeConnected_two.mpr ⟨hadj, h hadj.ne⟩

end SimpleGraph
```

-- snippet 30
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.reachable_eq_of_maximal_isAcyclic (L397-L412)
lemma reachable_eq_of_maximal_isAcyclic (F : SimpleGraph V)
    (h : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) F) : F.Reachable = G.Reachable := by
ext u v
  refine ⟨.mono h.prop.left, fun ⟨p⟩ ↦ ?_⟩
  by_contra
  let s : F.ConnectedComponent := .mk _ u
  have : v ∉ s := this ∘ s.reachable_of_mem_supp rfl
  have : ∃ d ∈ p.darts, d.fst ∈ s ∧ d.snd ∉ s := p.exists_boundary_dart s rfl this
  rcases this with ⟨⟨⟨u', v'⟩, huv⟩, _, hu, hv⟩
  have : ¬F.Reachable v' u' := mt ConnectedComponent.sound <| s.mem_supp_iff u' |>.mp hu ▸ hv
  suffices F ⊔ fromEdgeSet {s(v', u')} ≤ F by
    grind [Adj.reachable, sup_le_iff, le_iff_adj, fromEdgeSet_adj]
  refine h.le_of_ge ⟨?_, h.prop.right.isAcyclic_sup_fromEdgeSet_of_not_reachable this⟩ le_sup_left
  grind [Maximal, sup_le, le_iff_adj, fromEdgeSet_adj, huv.symm]

/-- A subgraph is maximal acyclic iff its reachability relation agrees with the larger graph. -/
```

-- snippet 31
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsAcyclic (L55-L57)
def IsAcyclic : Prop := ∀ ⦃v : V⦄ (c : G.Walk v v), ¬c.IsCycle
/-- A *tree* is a connected acyclic graph. -/
```

-- snippet 32
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_maximal_isAcyclic (L444-L449)
theorem isTree_iff_maximal_isAcyclic : G.IsTree ↔ Nonempty V ∧ Maximal IsAcyclic G := by
refine ⟨fun h ↦ ?_, fun ⟨_, h⟩ ↦ G.maximal_isAcyclic_iff_isTree.mp h⟩
  have := h.nonempty
  exact ⟨this, G.maximal_isAcyclic_iff_isTree.mpr h⟩

/-- Every acyclic subgraph can be extended to a spanning forest. -/
```

-- snippet 33
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_edge_isBridge (L181-L184)
theorem isAcyclic_iff_forall_edge_isBridge :
    G.IsAcyclic ↔ ∀ ⦃e⦄, e ∈ (G.edgeSet) → G.IsBridge e := by
simp [isAcyclic_iff_forall_adj_isBridge, Sym2.forall]
```

-- snippet 34
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sup_fromEdgeSet_iff (L380-L396)
theorem isAcyclic_sup_fromEdgeSet_iff {u v : V} :
    (G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic ↔
      G.IsAcyclic ∧ (G.Reachable u v → u = v ∨ G.Adj u v) := by
by_cases huv : u = v
  · grind [sup_eq_left, fromEdgeSet_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
  by_cases hadj : G.Adj u v
  · grind [sup_eq_left, fromEdgeSet_le, mem_edgeSet]
  refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.isAcyclic_sup_fromEdgeSet_of_not_reachable <| by grind⟩
  refine fun hacyc ↦ ⟨hacyc.anti le_sup_left, fun hreach ↦ False.elim ?_⟩
  have := isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]
  refine isBridge_iff.mp this |>.right <| hreach.mono <| Eq.le <| Eq.symm ?_
  rw [sup_sdiff_right_self]
  exact deleteEdges_eq_self.mpr <| Set.disjoint_singleton_right.mpr hadj

/--
The reachability relation of a maximal acyclic subgraph agrees with that of the larger graph.
-/
```

-- snippet 35
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_of_minimal_connected (L353-L359)
lemma isTree_of_minimal_connected (h : Minimal Connected G) : IsTree G := by
rw [isTree_iff, and_iff_right h.prop, isAcyclic_iff_forall_adj_isBridge]
  exact fun _ _ _ ↦ by_contra fun hbr ↦ h.not_prop_of_lt
    (by simpa [deleteEdges, ← edgeSet_ssubset_edgeSet])
    <| h.prop.connected_delete_edge_of_not_isBridge hbr

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 36
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_minimal_connected (L360-L368)
lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by
refine ⟨fun htree ↦ ⟨htree.connected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩
  have ⟨p, hp⟩ := h'.exists_isPath u v
  have := congrArg Walk.edges <| congrArg Subtype.val <|
    htree.isAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj
  simp only [edges_map, Hom.coe_ofLE, Sym2.map_id, List.map_id_fun, id_eq] at this
  simp [this, p.adj_of_mem_edges]

/-- Connecting two unreachable vertices by an edge preserves acyclicity. -/
```

-- snippet 37
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsTree (L154-L156)
lemma IsTree.of_subsingleton [Nonempty V] [Subsingleton V] {G : SimpleGraph V} : G.IsTree :=
⟨.of_subsingleton, .of_subsingleton⟩
```

-- snippet 38
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isCycle_of_two_le_isEdgeReachable (L642-L649)
lemma exists_isCycle_of_two_le_isEdgeReachable {u v : V} (huv : u ≠ v) {n : ℕ} (hn : 2 ≤ n)
    (h : G.IsEdgeReachable n u v) : ∃ w : G.Walk u u, w.IsCycle := by
classical
  obtain ⟨w, hw, h⟩ := exists_adj_isEdgeReachable_two huv (h.anti hn)
  have := @h {s(u, w)} (by simp)
  obtain ⟨w, p, hp₁, hp₂⟩ := adj_and_reachable_delete_edges_iff_exists_cycle.mp ⟨hw, this⟩
  exact ⟨p.rotate _ (p.fst_mem_support_of_mem_edges hp₂), IsCycle.rotate hp₁ _⟩
```

-- snippet 39
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le (L457-L462)
theorem exists_isAcyclic_reachable_eq_le :
    ∃ F ≤ G, F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic bot_le isAcyclic_bot
  grind

/-- Every acyclic subgraph of a connected graph can be extended to a spanning tree. -/
```

-- snippet 40
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_adj_isBridge (L167-L180)
theorem isAcyclic_iff_forall_adj_isBridge :
    G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge s(v, w) := by
simp_rw [isBridge_iff_adj_and_forall_cycle_notMem]
  constructor
  · intro ha v w hvw
    apply And.intro hvw
    intro u p hp
    cases ha p hp
  · rintro hb v (_ | ⟨ha, p⟩) hp
    · exact hp.not_of_nil
    · apply (hb ha).2 _ hp
      rw [Walk.edges_cons]
      apply List.mem_cons_self
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Combinatorics.SimpleGraph.Walks.Operations).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem nodup_tail_support_reverse {u : V} {p : G.Walk u u} :
    p.reverse.support.tail.Nodup ↔ p.support.tail.Nodup
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_rfl_rfl (L52-L53)
theorem copy_rfl_rfl {u v} (p : G.Walk u v) : p.copy rfl rfl = p := rfl
```

-- snippet 2
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_copy (L55-L60)
theorem copy_copy {u v u' v' u'' v''} (p : G.Walk u v)
    (hu : u = u') (hv : v = v') (hu' : u' = u'') (hv' : v' = v'') :
    (p.copy hu hv).copy hu' hv' = p.copy (hu.trans hu') (hv.trans hv') := by
subst_vars
  rfl
```

-- snippet 3
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_nil (L62-L65)
theorem copy_nil {u u'} (hu : u = u') : (Walk.nil : G.Walk u u).copy hu hu = nil := by
subst_vars
  rfl
```

-- snippet 4
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.copy_cons (L66-L70)
theorem copy_cons {u v w u' w'} (h : G.Adj u v) (p : G.Walk v w) (hu : u = u') (hw : w = w') :
    (Walk.cons h p).copy hu hw = Walk.cons (hu ▸ h) (p.copy rfl hw) := by
subst_vars
  rfl
```

-- snippet 5
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_copy (L72-L77)
theorem cons_copy {u v w v' w'} (h : G.Adj u v) (p : G.Walk v' w') (hv : v' = v) (hw : w' = w) :
    cons h (p.copy hv hw) = (Walk.cons (hv ▸ h) p).copy rfl hw := by
subst_vars
  rfl

/-- The concatenation of two compatible walks. -/
```

-- snippet 6
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append (L79-L84)
def append {u v w : V} : G.Walk u v → G.Walk v w → G.Walk u w
  | nil, q => q
  | cons h p, q => cons h (p.append q)

/-- The reversed version of `SimpleGraph.Walk.cons`, concatenating an edge to
the end of a walk. -/
```

-- snippet 7
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat (L85-L86)
def concat {u v w : V} (p : G.Walk u v) (h : G.Adj v w) : G.Walk u w := p.append (cons h nil)
```

-- snippet 8
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.concat_eq_append (L87-L95)
theorem concat_eq_append {u v w : V} (p : G.Walk u v) (h : G.Adj v w) :
    p.concat h = p.append (cons h nil) := rfl
/-- The concatenation of the reverse of the first walk with the second walk. -/
protected def reverseAux {u v w : V} : G.Walk u v → G.Walk u w → G.Walk v w
  | nil, q => q
  | cons h p, q => Walk.reverseAux p (cons (G.symm h) q)

/-- The walk in reverse. -/
```

-- snippet 9
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.reverse (L97-L98)
def reverse {u v : V} (w : G.Walk u v) : G.Walk v u := w.reverseAux nil
```

-- snippet 10
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_append (L100-L102)
theorem cons_append {u v w x : V} (h : G.Adj u v) (p : G.Walk v w) (q : G.Walk w x) :
    (cons h p).append q = cons h (p.append q) := rfl
```

-- snippet 11
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.cons_nil_append (L104-L106)
theorem cons_nil_append {u v w : V} (h : G.Adj u v) (p : G.Walk v w) :
    (cons h nil).append p = cons h p := rfl
```

-- snippet 12
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.nil_append (L108-L110)
theorem nil_append {u v : V} (p : G.Walk u v) : nil.append p = p :=
rfl
```

-- snippet 13
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_nil (L112-L114)
theorem append_nil {u v : V} (p : G.Walk u v) : p.append nil = p := by
induction p <;> simp [*]
```

-- snippet 14
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_assoc (L115-L118)
theorem append_assoc {u v w x : V} (p : G.Walk u v) (q : G.Walk v w) (r : G.Walk w x) :
    p.append (q.append r) = (p.append q).append r := by
induction p <;> simp [*]
```

-- snippet 15
```lean
-- Mathlib.Combinatorics.SimpleGraph.Walks.Operations.append_copy_copy (L120-L125)
theorem append_copy_copy {u v w u' v' w'} (p : G.Walk u v) (q : G.Walk v w)
    (hu : u = u') (hv : v = v') (hw : w = w') :
    (p.copy hu hv).append (q.copy hv hw) = (p.append q).copy hu hw := by
subst_vars
  rfl
```

-- snippet 16
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_add_edge_iff_of_not_reachable (L374-L379)
theorem isAcyclic_add_edge_iff_of_not_reachable (x y : V) (hxy : ¬ G.Reachable x y) :
    (G ⊔ fromEdgeSet {s(x, y)}).IsAcyclic ↔ IsAcyclic G :=
⟨.anti le_sup_left, .isAcyclic_sup_fromEdgeSet_of_not_reachable hxy⟩

/-- Adding an edge results in an acyclic graph iff the original graph was acyclic and
the edge connects vertices that previously had no path between them. -/
```

-- snippet 17
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_reachable_eq (L413-L427)
theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (hF : F.IsAcyclic) :
    Maximal (fun F ↦ F ≤ G ∧ F.IsAcyclic) F ↔ F.Reachable = G.Reachable := by
refine ⟨reachable_eq_of_maximal_isAcyclic F, fun h ↦ ?_⟩
  by_contra
  have ⟨H, hFH, hHG, hH⟩ := exists_gt_of_not_maximal ⟨hle, hF⟩ this
  have ⟨e, heH, heF⟩ := Set.exists_of_ssubset <| edgeSet_strict_mono hFH
  have h_bridge : (F ⊔ fromEdgeSet {e}).IsBridge e := by
    refine isAcyclic_iff_forall_edge_isBridge.mp ?_ <| by simp [H.not_isDiag_of_mem_edgeSet heH]
    exact hH.anti <| sup_le_iff.mpr ⟨hFH.le, H.fromEdgeSet_le.mpr <| by grind⟩
  have : (F ⊔ fromEdgeSet {e}) \ fromEdgeSet {e} = F := by simpa using heF
  cases e
  rw [isBridge_iff, this, h] at h_bridge
  exact h_bridge.right <| hHG heH |>.reachable

/-- A subgraph of a connected graph is maximal acyclic iff it is a tree. -/
```

-- snippet 18
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Subgraph (L151-L153)
lemma Subgraph.isAcyclic_coe_bot (G : SimpleGraph V) : (⊥ : G.Subgraph).coe.IsAcyclic :=
@IsAcyclic.of_subsingleton _ (Set.isEmpty_coe_sort.mpr rfl).instSubsingleton _
```

-- snippet 19
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Connected (L428-L436)
theorem Connected.maximal_le_isAcyclic_iff_isTree {T : SimpleGraph V} (hG : G.Connected)
    (hT : T ≤ G) : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) T ↔ T.IsTree := by
have := hG.nonempty
  refine ⟨fun h ↦ ⟨⟨fun u v ↦ ?_⟩, h.1.2⟩, fun hT' ↦ ?_⟩
  · exact G.reachable_eq_of_maximal_isAcyclic T h ▸ hG.preconnected u v
  · rw [maximal_isAcyclic_iff_reachable_eq hT hT'.isAcyclic,
      T.preconnected_iff_reachable_eq_top.mp hT'.preconnected,
      G.preconnected_iff_reachable_eq_top.mp hG.preconnected]
```

-- snippet 20
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_connected_and_card (L486-L499)
lemma isTree_iff_connected_and_card [Finite V] :
    G.IsTree ↔ G.Connected ∧ Nat.card G.edgeSet + 1 = Nat.card V := by
have := Fintype.ofFinite V
  classical
  refine ⟨fun h ↦ ⟨h.connected, by simpa [edgeFinset] using h.card_edgeFinset⟩,
    fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩⟩
  simp_rw [isAcyclic_iff_forall_adj_isBridge]
  refine fun x y h ↦ by_contra fun hbr ↦
    (h₁.connected_delete_edge_of_not_isBridge hbr).card_vert_le_card_edgeSet_add_one.not_gt ?_
  rw [Nat.card_eq_fintype_card, ← edgeFinset_card, ← h₂, Nat.card_eq_fintype_card,
    ← edgeFinset_card, add_lt_add_iff_right]
  exact Finset.card_lt_card <| by simpa [deleteEdges, edgeFinset]

/-- The minimum degree of all vertices in a nontrivial tree is one. -/
```

-- snippet 21
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sSup_of_isAcyclic_directedOn (L118-L126)
lemma isAcyclic_sSup_of_isAcyclic_directedOn (Hs : Set <| SimpleGraph V)
    (h_acyc : ∀ H ∈ Hs, H.IsAcyclic) (h_dir : DirectedOn (· ≤ ·) Hs) : IsAcyclic (sSup Hs) := by
rcases Hs.eq_empty_or_nonempty with rfl | hnemp
  · simp
  · intro u p hp
    obtain ⟨H, hH, hpH⟩ := p.exists_mem_contains_edges_of_directed Hs hnemp h_dir
    exact h_acyc H hH (p.transfer H hpH) <| Walk.IsCycle.transfer hp hpH

/-- Every acyclic subgraph `H ≤ G` is contained in a maximal such subgraph. -/
```

-- snippet 22
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_existsUnique_path (L248-L269)
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
classical
  rw [isTree_iff, isAcyclic_iff_path_unique]
  constructor
  · rintro ⟨hc, hu⟩
    refine ⟨hc.nonempty, ?_⟩
    intro v w
    let q := (hc v w).some.toPath
    use q
    simp only [true_and, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    refine ⟨Connected.mk ?_, ?_⟩
    · intro v w
      obtain ⟨p, _⟩ := h v w
      exact p.reachable
    · rintro v w ⟨p, hp⟩ ⟨q, hq⟩
      simp only [ExistsUnique.unique (h v w) hp hq]
```

-- snippet 23
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_path_unique (L225-L227)
theorem isAcyclic_iff_path_unique : G.IsAcyclic ↔ ∀ ⦃v w : V⦄ (p q : G.Path v w), p = q :=
⟨IsAcyclic.path_unique, isAcyclic_of_path_unique⟩
```

-- snippet 24
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_of_path_unique (L214-L224)
theorem isAcyclic_of_path_unique (h : ∀ (v w : V) (p q : G.Path v w), p = q) : G.IsAcyclic := by
intro v c hc
  simp only [Walk.isCycle_def, Ne] at hc
  cases c with
  | nil => cases hc.2.1 rfl
  | cons ha c' =>
    simp only [Walk.isTrail_cons, Walk.support_cons, List.tail_cons] at hc
    specialize h _ _ ⟨c', by simp only [Walk.isPath_def, hc.2]⟩ (Path.singleton ha.symm)
    rw [Path.singleton, Subtype.mk.injEq] at h
    simp [h] at hc
```

-- snippet 25
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic (L450-L456)
theorem exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic {H : SimpleGraph V} (hH_le : H ≤ G)
    (hH_isAcyclic : H.IsAcyclic) :
    ∃ F : SimpleGraph V, H ≤ F ∧ F ≤ G ∧ F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_maximal_isAcyclic_of_le_isAcyclic hH_le hH_isAcyclic
  grind [maximal_isAcyclic_iff_reachable_eq, Maximal]

/-- Every graph has a spanning forest. -/
```

-- snippet 26
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_maximal_isAcyclic_of_le_isAcyclic (L127-L135)
theorem exists_maximal_isAcyclic_of_le_isAcyclic
    {H : SimpleGraph V} (hHG : H ≤ G) (hH : H.IsAcyclic) :
    ∃ H' : SimpleGraph V, H ≤ H' ∧ Maximal (fun H => H ≤ G ∧ H.IsAcyclic) H' := by
refine zorn_le_nonempty₀ {H | H ≤ G ∧ H.IsAcyclic} (fun c hcs hc y hy ↦ ?_) _ ⟨hHG, hH⟩
  refine ⟨sSup c, ⟨?_, ?_⟩, fun _ ↦ le_sSup⟩
  · grind [sSup_le_iff]
  · exact isAcyclic_sSup_of_isAcyclic_directedOn c (by grind) hc.directedOn

/-- A connected component of an acyclic graph is a tree. -/
```

-- snippet 27
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.maximal_isAcyclic_iff_isTree (L438-L443)
theorem maximal_isAcyclic_iff_isTree [Nonempty V] {T : SimpleGraph V} :
    Maximal IsAcyclic T ↔ T.IsTree := by
simp [← connected_top.maximal_le_isAcyclic_iff_isTree le_top]

/-- A maximally acyclic graph is a tree. This is similar to `maximal_isAcyclic_iff_isTree` except
with `Nonempty V` as part of the iff rather than an assumption. -/
```

-- snippet 28
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.Iso (L80-L83)
lemma Iso.isAcyclic_iff (f : G ≃g G') : G.IsAcyclic ↔ G'.IsAcyclic :=
⟨fun h ↦ h.embedding f.symm, fun h ↦ h.embedding f⟩

/-- Isomorphic graphs are trees together. -/
```

-- snippet 29
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_pairwise_not_isEdgeReachable_two (L650-L658)
lemma isAcyclic_iff_pairwise_not_isEdgeReachable_two :
    G.IsAcyclic ↔ Pairwise (¬G.IsEdgeReachable 2 · ·) := by
refine ⟨fun h _ _ hne he ↦ ?_, fun h ↦ ?_⟩
  · obtain ⟨w, hw⟩ := exists_isCycle_of_two_le_isEdgeReachable hne le_rfl he
    exact h w hw
  · refine isAcyclic_iff_forall_adj_isBridge.mpr fun _ _ hadj ↦ ?_
    exact isBridge_iff_adj_and_not_isEdgeConnected_two.mpr ⟨hadj, h hadj.ne⟩

end SimpleGraph
```

-- snippet 30
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.reachable_eq_of_maximal_isAcyclic (L397-L412)
lemma reachable_eq_of_maximal_isAcyclic (F : SimpleGraph V)
    (h : Maximal (fun H ↦ H ≤ G ∧ H.IsAcyclic) F) : F.Reachable = G.Reachable := by
ext u v
  refine ⟨.mono h.prop.left, fun ⟨p⟩ ↦ ?_⟩
  by_contra
  let s : F.ConnectedComponent := .mk _ u
  have : v ∉ s := this ∘ s.reachable_of_mem_supp rfl
  have : ∃ d ∈ p.darts, d.fst ∈ s ∧ d.snd ∉ s := p.exists_boundary_dart s rfl this
  rcases this with ⟨⟨⟨u', v'⟩, huv⟩, _, hu, hv⟩
  have : ¬F.Reachable v' u' := mt ConnectedComponent.sound <| s.mem_supp_iff u' |>.mp hu ▸ hv
  suffices F ⊔ fromEdgeSet {s(v', u')} ≤ F by
    grind [Adj.reachable, sup_le_iff, le_iff_adj, fromEdgeSet_adj]
  refine h.le_of_ge ⟨?_, h.prop.right.isAcyclic_sup_fromEdgeSet_of_not_reachable this⟩ le_sup_left
  grind [Maximal, sup_le, le_iff_adj, fromEdgeSet_adj, huv.symm]

/-- A subgraph is maximal acyclic iff its reachability relation agrees with the larger graph. -/
```

-- snippet 31
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsAcyclic (L55-L57)
def IsAcyclic : Prop := ∀ ⦃v : V⦄ (c : G.Walk v v), ¬c.IsCycle
/-- A *tree* is a connected acyclic graph. -/
```

-- snippet 32
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_maximal_isAcyclic (L444-L449)
theorem isTree_iff_maximal_isAcyclic : G.IsTree ↔ Nonempty V ∧ Maximal IsAcyclic G := by
refine ⟨fun h ↦ ?_, fun ⟨_, h⟩ ↦ G.maximal_isAcyclic_iff_isTree.mp h⟩
  have := h.nonempty
  exact ⟨this, G.maximal_isAcyclic_iff_isTree.mpr h⟩

/-- Every acyclic subgraph can be extended to a spanning forest. -/
```

-- snippet 33
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_edge_isBridge (L181-L184)
theorem isAcyclic_iff_forall_edge_isBridge :
    G.IsAcyclic ↔ ∀ ⦃e⦄, e ∈ (G.edgeSet) → G.IsBridge e := by
simp [isAcyclic_iff_forall_adj_isBridge, Sym2.forall]
```

-- snippet 34
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_sup_fromEdgeSet_iff (L380-L396)
theorem isAcyclic_sup_fromEdgeSet_iff {u v : V} :
    (G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic ↔
      G.IsAcyclic ∧ (G.Reachable u v → u = v ∨ G.Adj u v) := by
by_cases huv : u = v
  · grind [sup_eq_left, fromEdgeSet_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
  by_cases hadj : G.Adj u v
  · grind [sup_eq_left, fromEdgeSet_le, mem_edgeSet]
  refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.isAcyclic_sup_fromEdgeSet_of_not_reachable <| by grind⟩
  refine fun hacyc ↦ ⟨hacyc.anti le_sup_left, fun hreach ↦ False.elim ?_⟩
  have := isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]
  refine isBridge_iff.mp this |>.right <| hreach.mono <| Eq.le <| Eq.symm ?_
  rw [sup_sdiff_right_self]
  exact deleteEdges_eq_self.mpr <| Set.disjoint_singleton_right.mpr hadj

/--
The reachability relation of a maximal acyclic subgraph agrees with that of the larger graph.
-/
```

-- snippet 35
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_of_minimal_connected (L353-L359)
lemma isTree_of_minimal_connected (h : Minimal Connected G) : IsTree G := by
rw [isTree_iff, and_iff_right h.prop, isAcyclic_iff_forall_adj_isBridge]
  exact fun _ _ _ ↦ by_contra fun hbr ↦ h.not_prop_of_lt
    (by simpa [deleteEdges, ← edgeSet_ssubset_edgeSet])
    <| h.prop.connected_delete_edge_of_not_isBridge hbr

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 36
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isTree_iff_minimal_connected (L360-L368)
lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by
refine ⟨fun htree ↦ ⟨htree.connected, fun G' h' hle u v hadj ↦ ?_⟩, isTree_of_minimal_connected⟩
  have ⟨p, hp⟩ := h'.exists_isPath u v
  have := congrArg Walk.edges <| congrArg Subtype.val <|
    htree.isAcyclic.path_unique ⟨p.mapLe hle, hp.mapLe hle⟩ <| Path.singleton hadj
  simp only [edges_map, Hom.coe_ofLE, Sym2.map_id, List.map_id_fun, id_eq] at this
  simp [this, p.adj_of_mem_edges]

/-- Connecting two unreachable vertices by an edge preserves acyclicity. -/
```

-- snippet 37
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.IsTree (L154-L156)
lemma IsTree.of_subsingleton [Nonempty V] [Subsingleton V] {G : SimpleGraph V} : G.IsTree :=
⟨.of_subsingleton, .of_subsingleton⟩
```

-- snippet 38
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isCycle_of_two_le_isEdgeReachable (L642-L649)
lemma exists_isCycle_of_two_le_isEdgeReachable {u v : V} (huv : u ≠ v) {n : ℕ} (hn : 2 ≤ n)
    (h : G.IsEdgeReachable n u v) : ∃ w : G.Walk u u, w.IsCycle := by
classical
  obtain ⟨w, hw, h⟩ := exists_adj_isEdgeReachable_two huv (h.anti hn)
  have := @h {s(u, w)} (by simp)
  obtain ⟨w, p, hp₁, hp₂⟩ := adj_and_reachable_delete_edges_iff_exists_cycle.mp ⟨hw, this⟩
  exact ⟨p.rotate _ (p.fst_mem_support_of_mem_edges hp₂), IsCycle.rotate hp₁ _⟩
```

-- snippet 39
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.exists_isAcyclic_reachable_eq_le (L457-L462)
theorem exists_isAcyclic_reachable_eq_le :
    ∃ F ≤ G, F.IsAcyclic ∧ F.Reachable = G.Reachable := by
obtain ⟨F, hF⟩ := G.exists_isAcyclic_reachable_eq_le_of_le_of_isAcyclic bot_le isAcyclic_bot
  grind

/-- Every acyclic subgraph of a connected graph can be extended to a spanning tree. -/
```

-- snippet 40
```lean
-- Mathlib.Combinatorics.SimpleGraph.Acyclic.isAcyclic_iff_forall_adj_isBridge (L167-L180)
theorem isAcyclic_iff_forall_adj_isBridge :
    G.IsAcyclic ↔ ∀ ⦃v w : V⦄, G.Adj v w → G.IsBridge s(v, w) := by
simp_rw [isBridge_iff_adj_and_forall_cycle_notMem]
  constructor
  · intro ha v w hvw
    apply And.intro hvw
    intro u p hp
    cases ha p hp
  · rintro hb v (_ | ⟨ha, p⟩) hp
    · exact hp.not_of_nil
    · apply (hb ha).2 _ hp
      rw [Walk.edges_cons]
      apply List.mem_cons_self
```
[/INST]

mistral-common:Tekken v15 (Mistral chat template, [INST]/[SYSTEM_PROMPT])


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.Fintype.Card).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem card_range {α β F : Type*} [FunLike F α β] [EmbeddingLike F α β] (f : F) [Fintype α]
    [Fintype (Set.range f)] : Fintype.card (Set.range f) = Fintype.card α
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.Fintype.Card.card (L40-L42)
def card (α) [Fintype α] : ℕ :=
(@univ α _).card
```

-- snippet 2
```lean
-- Mathlib.Data.Fintype.Card.subtype_card (L43-L46)
theorem subtype_card {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x) :
    @card { x // p x } (Fintype.subtype s H) = #s :=
Multiset.card_pmap _ _ _
```

-- snippet 3
```lean
-- Mathlib.Data.Fintype.Card.card_of_subtype (L47-L51)
theorem card_of_subtype {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x)
    [Fintype { x // p x }] : card { x // p x } = #s := by
rw [← subtype_card s H]
  congr!
```

-- snippet 4
```lean
-- Mathlib.Data.Fintype.Card.card_ofFinset (L53-L56)
theorem card_ofFinset {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) :
    @Fintype.card p (ofFinset s H) = #s :=
Fintype.subtype_card s H
```

-- snippet 5
```lean
-- Mathlib.Data.Fintype.Card.card_of_finset' (L57-L63)
theorem card_of_finset' {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) [Fintype p] :
    Fintype.card p = #s := by rw [← card_ofFinset s H]; congr!
end Fintype

namespace Fintype
```

-- snippet 6
```lean
-- Mathlib.Data.Fintype.Card.ofEquiv_card (L64-L66)
theorem ofEquiv_card [Fintype α] (f : α ≃ β) : @card β (ofEquiv α f) = card α :=
Multiset.card_map _ _
```

-- snippet 7
```lean
-- Mathlib.Data.Fintype.Card.card_congr (L67-L69)
theorem card_congr {α β} [Fintype α] [Fintype β] (f : α ≃ β) : card α = card β := by
rw [← ofEquiv_card f]; congr!
```

-- snippet 8
```lean
-- Mathlib.Data.Fintype.Card.card_congr' (L71-L76)
theorem card_congr' {α β} [Fintype α] [Fintype β] (h : α = β) : card α = card β :=
card_congr (by rw [h])

/-- Note: this lemma is specifically about `Fintype.ofSubsingleton`. For a statement about
arbitrary `Fintype` instances, use either `Fintype.card_le_one_iff_subsingleton` or
`Fintype.card_unique`. -/
```

-- snippet 9
```lean
-- Mathlib.Data.Fintype.Card.card_ofSubsingleton (L77-L79)
theorem card_ofSubsingleton (a : α) [Subsingleton α] : @Fintype.card _ (ofSubsingleton a) = 1 :=
rfl
```

-- snippet 10
```lean
-- Mathlib.Data.Fintype.Card.card_unique (L81-L85)
theorem card_unique [Unique α] [h : Fintype α] : Fintype.card α = 1 :=
Subsingleton.elim (ofSubsingleton default) h ▸ card_ofSubsingleton _

/-- Note: this lemma is specifically about `Fintype.ofIsEmpty`. For a statement about
arbitrary `Fintype` instances, use `Fintype.card_eq_zero`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.Fintype.Card.card_ofIsEmpty (L86-L96)
theorem card_ofIsEmpty [IsEmpty α] : @Fintype.card α Fintype.ofIsEmpty = 0 :=
rfl

end Fintype

namespace Set

variable {s t : Set α}

-- We use an arbitrary `[Fintype s]` instance here,
-- not necessarily coming from a `[Fintype α]`.
```

-- snippet 12
```lean
-- Mathlib.Data.Fintype.Card.toFinset_card (L98-L102)
theorem toFinset_card {α : Type*} (s : Set α) [Fintype s] : s.toFinset.card = Fintype.card s :=
Multiset.card_map Subtype.val Finset.univ.val

end Set
```

-- snippet 13
```lean
-- Mathlib.Data.Fintype.Card.Finset (L104-L105)
theorem Finset.card_univ [Fintype α] : #(univ : Finset α) = Fintype.card α := rfl
```

-- snippet 14
```lean
-- Mathlib.Data.Fintype.Card.Finset (L106-L109)
theorem Finset.eq_univ_of_card [Fintype α] (s : Finset α) (hs : #s = Fintype.card α) :
    s = univ :=
eq_of_subset_of_card_le (subset_univ _) <| by rw [hs, Finset.card_univ]
```

-- snippet 15
```lean
-- Mathlib.Data.Fintype.Card.Finset (L110-L114)
theorem Finset.card_eq_iff_eq_univ [Fintype α] (s : Finset α) : #s = Fintype.card α ↔ s = univ :=
⟨s.eq_univ_of_card, by
    rintro rfl
    exact Finset.card_univ⟩
```

-- snippet 16
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_extend_by_one (L55-L58)
theorem prod_extend_by_one [CommMonoid α] (s : Finset ι) (f : ι → α) :
    ∏ i, (if i ∈ s then f i else 1) = ∏ i ∈ s, f i := by
rw [← prod_filter, filter_mem_eq_inter, univ_inter]
```

-- snippet 17
```lean
-- Mathlib.Data.Fintype.Basic.count_univ (L223-L225)
theorem count_univ [DecidableEq α] (a : α) : count a Finset.univ.val = 1 :=
count_eq_one_of_mem Finset.univ.nodup (Finset.mem_univ _)
```

-- snippet 18
```lean
-- Mathlib.Data.Fintype.Basic.map_univ_val_equiv (L227-L231)
theorem map_univ_val_equiv (e : α ≃ β) :
    map e univ.val = univ.val := by
rw [← congr_arg Finset.val (Finset.map_univ_equiv e), Finset.map_val, Equiv.coe_toEmbedding]

/-- For functions on finite sets, they are bijections iff they map universes into universes. -/
```

-- snippet 19
```lean
-- Mathlib.Data.Fintype.Basic.exists_seq_of_forall_finset_exists (L258-L291)
theorem exists_seq_of_forall_finset_exists {α : Type*} (P : α → Prop) (r : α → α → Prop)
    (h : ∀ s : Finset α, (∀ x ∈ s, P x) → ∃ y, P y ∧ ∀ x ∈ s, r x y) :
    ∃ f : ℕ → α, (∀ n, P (f n)) ∧ ∀ m n, m < n → r (f m) (f n) := by
classical
    have : Nonempty α := by
      rcases h ∅ (by simp) with ⟨y, _⟩
      exact ⟨y⟩
    choose! F hF using h
    have h' : ∀ s : Finset α, ∃ y, (∀ x ∈ s, P x) → P y ∧ ∀ x ∈ s, r x y := fun s => ⟨F s, hF s⟩
    set f := seqOfForallFinsetExistsAux P r h' with hf
    have A : ∀ n : ℕ, P (f n) := by
      intro n
      induction n using Nat.strong_induction_on with | _ n IH
      have IH' : ∀ x : Fin n, P (f x) := fun n => IH n.1 n.2
      rw [hf, seqOfForallFinsetExistsAux]
      exact
        (Classical.choose_spec
            (h' (Finset.image (fun i : Fin n => f i) (Finset.univ : Finset (Fin n))))
            (by simp [IH'])).1
    refine ⟨f, A, fun m n hmn => ?_⟩
    conv_rhs => rw [hf]
    rw [seqOfForallFinsetExistsAux]
    apply
      (Classical.choose_spec
          (h' (Finset.image (fun i : Fin n => f i) (Finset.univ : Finset (Fin n)))) (by simp [A])).2
    exact Finset.mem_image.2 ⟨⟨m, hmn⟩, Finset.mem_univ _, rfl⟩

/-- Induction principle to build a sequence, by adding one point at a time satisfying a given
symmetric relation with respect to all the previously chosen points.

More precisely, Assume that, for any finite set `s`, one can find another point satisfying
some relation `r` with respect to all the points in `s`. Then one may construct a
function `f : ℕ → α` such that `r (f m) (f n)` holds whenever `m ≠ n`.
We also ensure that all constructed points satisfy a given predicate `P`. -/
```

-- snippet 20
```lean
-- Mathlib.Data.Fintype.Basic.PUnit (L140-L142)
instance PUnit.fintype : Fintype PUnit :=
Fintype.ofSubsingleton PUnit.unit
```

-- snippet 21
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_bool (L43-L44)
theorem prod_bool [CommMonoid α] (f : Bool → α) : ∏ b, f b = f true * f false := by simp
```

-- snippet 22
```lean
-- Mathlib.Data.Fintype.Basic.nonempty_fintype (L47-L50)
theorem nonempty_fintype (α : Type*) [Finite α] : Nonempty (Fintype α) := by
rcases Finite.exists_equiv_fin α with ⟨n, ⟨e⟩⟩
  exact ⟨.ofEquiv _ e.symm⟩
```

-- snippet 23
```lean
-- Mathlib.Data.Fintype.Basic.truncOfNonemptyFintype (L206-L211)
def truncOfNonemptyFintype (α) [Nonempty α] [Fintype α] : Trunc α :=
truncOfMultisetExistsMem Finset.univ.val (by simp)

/-- By iterating over the elements of a fintype, we can lift an existential statement `∃ a, P a`
to `Trunc (Σ' a, P a)`, containing data.
-/
```

-- snippet 24
```lean
-- Mathlib.Data.Fintype.Basic.Fintype (L120-L124)
instance Fintype.subtypeEq (y : α) : Fintype { x // x = y } :=
Fintype.subtype {y} (by simp)

/-- Short-circuit instance to decrease search for `Unique.fintype`,
since that relies on a subsingleton elimination for `Unique`. -/
```

-- snippet 25
```lean
-- Mathlib.Data.Fintype.Basic.truncOfMultisetExistsMem (L198-L205)
def truncOfMultisetExistsMem {α} (s : Multiset α) : (∃ x, x ∈ s) → Trunc α :=
Quotient.recOnSubsingleton s fun l h =>
    match l, h with
    | [], _ => False.elim (by tauto)
    | a :: _, _ => Trunc.mk a

/-- A `Nonempty` `Fintype` constructively contains an element.
-/
```

-- snippet 26
```lean
-- Mathlib.Data.Fintype.Basic.Unit (L134-L136)
instance Unit.fintype : Fintype Unit :=
Fintype.ofSubsingleton ()
```

-- snippet 27
```lean
-- Mathlib.Data.Fintype.Basic.PLift (L163-L165)
instance PLift.fintype (α : Type*) [Fintype α] : Fintype (PLift α) :=
Fintype.ofEquiv _ Equiv.plift.symm
```

-- snippet 28
```lean
-- Mathlib.Data.Fintype.Basic.pfunFintype (L188-L197)
instance pfunFintype (p : Prop) [Decidable p] (α : p → Type*) [∀ hp, Fintype (α hp)] :
    Fintype (∀ hp : p, α hp) :=
if hp : p then Fintype.ofEquiv (α hp) ⟨fun a _ => a, fun f => f hp, fun _ => rfl, fun _ => rfl⟩
  else ⟨singleton fun h => (hp h).elim, fun h => mem_singleton.2
    (funext fun x => by contradiction)⟩

section Trunc

/-- For `s : Multiset α`, we can lift the existential statement that `∃ x, x ∈ s` to a `Trunc α`.
-/
```

-- snippet 29
```lean
-- Mathlib.Data.Fintype.Basic.Fin (L36-L38)
instance Fin.fintype (n : ℕ) : Fintype (Fin n) :=
⟨⟨List.finRange n, List.nodup_finRange n⟩, List.mem_finRange⟩
```

-- snippet 30
```lean
-- Mathlib.Data.Fintype.Basic.Quotient (L169-L172)
instance Quotient.fintype [Fintype α] (s : Setoid α) [DecidableRel ((· ≈ ·) : α → α → Prop)] :
    Fintype (Quotient s) :=
Fintype.ofSurjective Quotient.mk'' Quotient.mk''_surjective
```

-- snippet 31
```lean
-- Mathlib.Data.Fintype.Basic.exists_seq_of_forall_finset_exists' (L292-L297)
theorem exists_seq_of_forall_finset_exists' {α : Type*} (P : α → Prop) (r : α → α → Prop)
    [Std.Symm r] (h : ∀ s : Finset α, (∀ x ∈ s, P x) → ∃ y, P y ∧ ∀ x ∈ s, r x y) :
    ∃ f : ℕ → α, (∀ n, P (f n)) ∧ Pairwise (r on f) := by
rcases exists_seq_of_forall_finset_exists P r h with ⟨f, hf, hf'⟩
  refine ⟨f, hf, fun m n hmn => ?_⟩
  grind +splitIndPred
```

-- snippet 32
```lean
-- Mathlib.Data.Fintype.BigOperators.card_eq_sum_ones (L45-L47)
theorem card_eq_sum_ones {α} [Fintype α] : Fintype.card α = ∑ _a : α, 1 :=
Finset.card_eq_sum_ones _
```

-- snippet 33
```lean
-- Mathlib.Data.Fintype.Basic.Finset (L42-L43)
theorem Finset.univ_fin2 : (univ : Finset (Fin 2)) = {0, 1} := rfl
```

-- snippet 34
```lean
-- Mathlib.Data.Fintype.Basic.bijective_iff_map_univ_eq_univ (L233-L257)
theorem bijective_iff_map_univ_eq_univ (f : α → β) :
    f.Bijective ↔ map f (Finset.univ : Finset α).val = univ.val :=
⟨fun bij ↦ congr_arg (·.val) (map_univ_equiv <| Equiv.ofBijective f bij),
    fun eq ↦ ⟨
      fun a₁ a₂ ↦ inj_on_of_nodup_map (eq.symm ▸ univ.nodup) _ (mem_univ a₁) _ (mem_univ a₂),
      fun b ↦ have ⟨a, _, h⟩ := mem_map.mp (eq.symm ▸ mem_univ_val b); ⟨a, h⟩⟩⟩

end Multiset

/-- Auxiliary definition to show `exists_seq_of_forall_finset_exists`. -/
noncomputable def seqOfForallFinsetExistsAux {α : Type*} [DecidableEq α] (P : α → Prop)
    (r : α → α → Prop) (h : ∀ s : Finset α, ∃ y, (∀ x ∈ s, P x) → P y ∧ ∀ x ∈ s, r x y) : ℕ → α
  | n =>
    Classical.choose
      (h
        (Finset.image (fun i : Fin n => seqOfForallFinsetExistsAux P r h i)
          (Finset.univ : Finset (Fin n))))

/-- Induction principle to build a sequence, by adding one point at a time satisfying a given
relation with respect to all the previously chosen points.

More precisely, Assume that, for any finite set `s`, one can find another point satisfying
some relation `r` with respect to all the points in `s`. Then one may construct a
function `f : ℕ → α` such that `r (f m) (f n)` holds whenever `m < n`.
We also ensure that all constructed points satisfy a given predicate `P`. -/
```

-- snippet 35
```lean
-- Mathlib.Data.Fintype.Basic.truncSigmaOfExists (L212-L221)
def truncSigmaOfExists {α} [Fintype α] {P : α → Prop} [DecidablePred P] (h : ∃ a, P a) :
    Trunc (Σ' a, P a) :=
@truncOfNonemptyFintype (Σ' a, P a) ((Exists.elim h) fun a ha => ⟨⟨a, ha⟩⟩) _

end Trunc

namespace Multiset

variable [Fintype α] [Fintype β]
```

-- snippet 36
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_congr (L70-L72)
theorem prod_congr (f g : α → M) (h : ∀ a, f a = g a) : ∏ a, f a = ∏ a, g a :=
Finset.prod_congr rfl fun a _ha => h a
```

-- snippet 37
```lean
-- Mathlib.Data.Fintype.Basic.Unique (L115-L119)
instance Unique.fintype {α : Type*} [Unique α] : Fintype α :=
Fintype.ofSubsingleton default

/-- Short-circuit instance to decrease search for `Unique.fintype`,
since that relies on a subsingleton elimination for `Unique`. -/
```

-- snippet 38
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_eq_one (L66-L68)
theorem prod_eq_one (f : α → M) (h : ∀ a, f a = 1) : ∏ a, f a = 1 :=
Finset.prod_eq_one fun a _ha => h a
```

-- snippet 39
```lean
-- Mathlib.Data.Fintype.Basic.PSigma (L173-L177)
instance PSigma.fintypePropLeft {α : Prop} {β : α → Type*} [Decidable α] [∀ a, Fintype (β a)] :
    Fintype (Σ' a, β a) :=
if h : α then Fintype.ofEquiv (β h) ⟨fun x => ⟨h, x⟩, PSigma.snd, fun _ => rfl, fun ⟨_, _⟩ => rfl⟩
  else ⟨∅, fun x => (h x.1).elim⟩
```

-- snippet 40
```lean
-- Mathlib.Data.Fintype.Basic.ULift (L160-L162)
instance ULift.fintype (α : Type*) [Fintype α] : Fintype (ULift α) :=
Fintype.ofEquiv _ Equiv.ulift.symm
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.Fintype.Card).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem card_range {α β F : Type*} [FunLike F α β] [EmbeddingLike F α β] (f : F) [Fintype α]
    [Fintype (Set.range f)] : Fintype.card (Set.range f) = Fintype.card α
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.Fintype.Card.card (L40-L42)
def card (α) [Fintype α] : ℕ :=
(@univ α _).card
```

-- snippet 2
```lean
-- Mathlib.Data.Fintype.Card.subtype_card (L43-L46)
theorem subtype_card {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x) :
    @card { x // p x } (Fintype.subtype s H) = #s :=
Multiset.card_pmap _ _ _
```

-- snippet 3
```lean
-- Mathlib.Data.Fintype.Card.card_of_subtype (L47-L51)
theorem card_of_subtype {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x)
    [Fintype { x // p x }] : card { x // p x } = #s := by
rw [← subtype_card s H]
  congr!
```

-- snippet 4
```lean
-- Mathlib.Data.Fintype.Card.card_ofFinset (L53-L56)
theorem card_ofFinset {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) :
    @Fintype.card p (ofFinset s H) = #s :=
Fintype.subtype_card s H
```

-- snippet 5
```lean
-- Mathlib.Data.Fintype.Card.card_of_finset' (L57-L63)
theorem card_of_finset' {p : Set α} (s : Finset α) (H : ∀ x, x ∈ s ↔ x ∈ p) [Fintype p] :
    Fintype.card p = #s := by rw [← card_ofFinset s H]; congr!
end Fintype

namespace Fintype
```

-- snippet 6
```lean
-- Mathlib.Data.Fintype.Card.ofEquiv_card (L64-L66)
theorem ofEquiv_card [Fintype α] (f : α ≃ β) : @card β (ofEquiv α f) = card α :=
Multiset.card_map _ _
```

-- snippet 7
```lean
-- Mathlib.Data.Fintype.Card.card_congr (L67-L69)
theorem card_congr {α β} [Fintype α] [Fintype β] (f : α ≃ β) : card α = card β := by
rw [← ofEquiv_card f]; congr!
```

-- snippet 8
```lean
-- Mathlib.Data.Fintype.Card.card_congr' (L71-L76)
theorem card_congr' {α β} [Fintype α] [Fintype β] (h : α = β) : card α = card β :=
card_congr (by rw [h])

/-- Note: this lemma is specifically about `Fintype.ofSubsingleton`. For a statement about
arbitrary `Fintype` instances, use either `Fintype.card_le_one_iff_subsingleton` or
`Fintype.card_unique`. -/
```

-- snippet 9
```lean
-- Mathlib.Data.Fintype.Card.card_ofSubsingleton (L77-L79)
theorem card_ofSubsingleton (a : α) [Subsingleton α] : @Fintype.card _ (ofSubsingleton a) = 1 :=
rfl
```

-- snippet 10
```lean
-- Mathlib.Data.Fintype.Card.card_unique (L81-L85)
theorem card_unique [Unique α] [h : Fintype α] : Fintype.card α = 1 :=
Subsingleton.elim (ofSubsingleton default) h ▸ card_ofSubsingleton _

/-- Note: this lemma is specifically about `Fintype.ofIsEmpty`. For a statement about
arbitrary `Fintype` instances, use `Fintype.card_eq_zero`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.Fintype.Card.card_ofIsEmpty (L86-L96)
theorem card_ofIsEmpty [IsEmpty α] : @Fintype.card α Fintype.ofIsEmpty = 0 :=
rfl

end Fintype

namespace Set

variable {s t : Set α}

-- We use an arbitrary `[Fintype s]` instance here,
-- not necessarily coming from a `[Fintype α]`.
```

-- snippet 12
```lean
-- Mathlib.Data.Fintype.Card.toFinset_card (L98-L102)
theorem toFinset_card {α : Type*} (s : Set α) [Fintype s] : s.toFinset.card = Fintype.card s :=
Multiset.card_map Subtype.val Finset.univ.val

end Set
```

-- snippet 13
```lean
-- Mathlib.Data.Fintype.Card.Finset (L104-L105)
theorem Finset.card_univ [Fintype α] : #(univ : Finset α) = Fintype.card α := rfl
```

-- snippet 14
```lean
-- Mathlib.Data.Fintype.Card.Finset (L106-L109)
theorem Finset.eq_univ_of_card [Fintype α] (s : Finset α) (hs : #s = Fintype.card α) :
    s = univ :=
eq_of_subset_of_card_le (subset_univ _) <| by rw [hs, Finset.card_univ]
```

-- snippet 15
```lean
-- Mathlib.Data.Fintype.Card.Finset (L110-L114)
theorem Finset.card_eq_iff_eq_univ [Fintype α] (s : Finset α) : #s = Fintype.card α ↔ s = univ :=
⟨s.eq_univ_of_card, by
    rintro rfl
    exact Finset.card_univ⟩
```

-- snippet 16
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_extend_by_one (L55-L58)
theorem prod_extend_by_one [CommMonoid α] (s : Finset ι) (f : ι → α) :
    ∏ i, (if i ∈ s then f i else 1) = ∏ i ∈ s, f i := by
rw [← prod_filter, filter_mem_eq_inter, univ_inter]
```

-- snippet 17
```lean
-- Mathlib.Data.Fintype.Basic.count_univ (L223-L225)
theorem count_univ [DecidableEq α] (a : α) : count a Finset.univ.val = 1 :=
count_eq_one_of_mem Finset.univ.nodup (Finset.mem_univ _)
```

-- snippet 18
```lean
-- Mathlib.Data.Fintype.Basic.map_univ_val_equiv (L227-L231)
theorem map_univ_val_equiv (e : α ≃ β) :
    map e univ.val = univ.val := by
rw [← congr_arg Finset.val (Finset.map_univ_equiv e), Finset.map_val, Equiv.coe_toEmbedding]

/-- For functions on finite sets, they are bijections iff they map universes into universes. -/
```

-- snippet 19
```lean
-- Mathlib.Data.Fintype.Basic.exists_seq_of_forall_finset_exists (L258-L291)
theorem exists_seq_of_forall_finset_exists {α : Type*} (P : α → Prop) (r : α → α → Prop)
    (h : ∀ s : Finset α, (∀ x ∈ s, P x) → ∃ y, P y ∧ ∀ x ∈ s, r x y) :
    ∃ f : ℕ → α, (∀ n, P (f n)) ∧ ∀ m n, m < n → r (f m) (f n) := by
classical
    have : Nonempty α := by
      rcases h ∅ (by simp) with ⟨y, _⟩
      exact ⟨y⟩
    choose! F hF using h
    have h' : ∀ s : Finset α, ∃ y, (∀ x ∈ s, P x) → P y ∧ ∀ x ∈ s, r x y := fun s => ⟨F s, hF s⟩
    set f := seqOfForallFinsetExistsAux P r h' with hf
    have A : ∀ n : ℕ, P (f n) := by
      intro n
      induction n using Nat.strong_induction_on with | _ n IH
      have IH' : ∀ x : Fin n, P (f x) := fun n => IH n.1 n.2
      rw [hf, seqOfForallFinsetExistsAux]
      exact
        (Classical.choose_spec
            (h' (Finset.image (fun i : Fin n => f i) (Finset.univ : Finset (Fin n))))
            (by simp [IH'])).1
    refine ⟨f, A, fun m n hmn => ?_⟩
    conv_rhs => rw [hf]
    rw [seqOfForallFinsetExistsAux]
    apply
      (Classical.choose_spec
          (h' (Finset.image (fun i : Fin n => f i) (Finset.univ : Finset (Fin n)))) (by simp [A])).2
    exact Finset.mem_image.2 ⟨⟨m, hmn⟩, Finset.mem_univ _, rfl⟩

/-- Induction principle to build a sequence, by adding one point at a time satisfying a given
symmetric relation with respect to all the previously chosen points.

More precisely, Assume that, for any finite set `s`, one can find another point satisfying
some relation `r` with respect to all the points in `s`. Then one may construct a
function `f : ℕ → α` such that `r (f m) (f n)` holds whenever `m ≠ n`.
We also ensure that all constructed points satisfy a given predicate `P`. -/
```

-- snippet 20
```lean
-- Mathlib.Data.Fintype.Basic.PUnit (L140-L142)
instance PUnit.fintype : Fintype PUnit :=
Fintype.ofSubsingleton PUnit.unit
```

-- snippet 21
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_bool (L43-L44)
theorem prod_bool [CommMonoid α] (f : Bool → α) : ∏ b, f b = f true * f false := by simp
```

-- snippet 22
```lean
-- Mathlib.Data.Fintype.Basic.nonempty_fintype (L47-L50)
theorem nonempty_fintype (α : Type*) [Finite α] : Nonempty (Fintype α) := by
rcases Finite.exists_equiv_fin α with ⟨n, ⟨e⟩⟩
  exact ⟨.ofEquiv _ e.symm⟩
```

-- snippet 23
```lean
-- Mathlib.Data.Fintype.Basic.truncOfNonemptyFintype (L206-L211)
def truncOfNonemptyFintype (α) [Nonempty α] [Fintype α] : Trunc α :=
truncOfMultisetExistsMem Finset.univ.val (by simp)

/-- By iterating over the elements of a fintype, we can lift an existential statement `∃ a, P a`
to `Trunc (Σ' a, P a)`, containing data.
-/
```

-- snippet 24
```lean
-- Mathlib.Data.Fintype.Basic.Fintype (L120-L124)
instance Fintype.subtypeEq (y : α) : Fintype { x // x = y } :=
Fintype.subtype {y} (by simp)

/-- Short-circuit instance to decrease search for `Unique.fintype`,
since that relies on a subsingleton elimination for `Unique`. -/
```

-- snippet 25
```lean
-- Mathlib.Data.Fintype.Basic.truncOfMultisetExistsMem (L198-L205)
def truncOfMultisetExistsMem {α} (s : Multiset α) : (∃ x, x ∈ s) → Trunc α :=
Quotient.recOnSubsingleton s fun l h =>
    match l, h with
    | [], _ => False.elim (by tauto)
    | a :: _, _ => Trunc.mk a

/-- A `Nonempty` `Fintype` constructively contains an element.
-/
```

-- snippet 26
```lean
-- Mathlib.Data.Fintype.Basic.Unit (L134-L136)
instance Unit.fintype : Fintype Unit :=
Fintype.ofSubsingleton ()
```

-- snippet 27
```lean
-- Mathlib.Data.Fintype.Basic.PLift (L163-L165)
instance PLift.fintype (α : Type*) [Fintype α] : Fintype (PLift α) :=
Fintype.ofEquiv _ Equiv.plift.symm
```

-- snippet 28
```lean
-- Mathlib.Data.Fintype.Basic.pfunFintype (L188-L197)
instance pfunFintype (p : Prop) [Decidable p] (α : p → Type*) [∀ hp, Fintype (α hp)] :
    Fintype (∀ hp : p, α hp) :=
if hp : p then Fintype.ofEquiv (α hp) ⟨fun a _ => a, fun f => f hp, fun _ => rfl, fun _ => rfl⟩
  else ⟨singleton fun h => (hp h).elim, fun h => mem_singleton.2
    (funext fun x => by contradiction)⟩

section Trunc

/-- For `s : Multiset α`, we can lift the existential statement that `∃ x, x ∈ s` to a `Trunc α`.
-/
```

-- snippet 29
```lean
-- Mathlib.Data.Fintype.Basic.Fin (L36-L38)
instance Fin.fintype (n : ℕ) : Fintype (Fin n) :=
⟨⟨List.finRange n, List.nodup_finRange n⟩, List.mem_finRange⟩
```

-- snippet 30
```lean
-- Mathlib.Data.Fintype.Basic.Quotient (L169-L172)
instance Quotient.fintype [Fintype α] (s : Setoid α) [DecidableRel ((· ≈ ·) : α → α → Prop)] :
    Fintype (Quotient s) :=
Fintype.ofSurjective Quotient.mk'' Quotient.mk''_surjective
```

-- snippet 31
```lean
-- Mathlib.Data.Fintype.Basic.exists_seq_of_forall_finset_exists' (L292-L297)
theorem exists_seq_of_forall_finset_exists' {α : Type*} (P : α → Prop) (r : α → α → Prop)
    [Std.Symm r] (h : ∀ s : Finset α, (∀ x ∈ s, P x) → ∃ y, P y ∧ ∀ x ∈ s, r x y) :
    ∃ f : ℕ → α, (∀ n, P (f n)) ∧ Pairwise (r on f) := by
rcases exists_seq_of_forall_finset_exists P r h with ⟨f, hf, hf'⟩
  refine ⟨f, hf, fun m n hmn => ?_⟩
  grind +splitIndPred
```

-- snippet 32
```lean
-- Mathlib.Data.Fintype.BigOperators.card_eq_sum_ones (L45-L47)
theorem card_eq_sum_ones {α} [Fintype α] : Fintype.card α = ∑ _a : α, 1 :=
Finset.card_eq_sum_ones _
```

-- snippet 33
```lean
-- Mathlib.Data.Fintype.Basic.Finset (L42-L43)
theorem Finset.univ_fin2 : (univ : Finset (Fin 2)) = {0, 1} := rfl
```

-- snippet 34
```lean
-- Mathlib.Data.Fintype.Basic.bijective_iff_map_univ_eq_univ (L233-L257)
theorem bijective_iff_map_univ_eq_univ (f : α → β) :
    f.Bijective ↔ map f (Finset.univ : Finset α).val = univ.val :=
⟨fun bij ↦ congr_arg (·.val) (map_univ_equiv <| Equiv.ofBijective f bij),
    fun eq ↦ ⟨
      fun a₁ a₂ ↦ inj_on_of_nodup_map (eq.symm ▸ univ.nodup) _ (mem_univ a₁) _ (mem_univ a₂),
      fun b ↦ have ⟨a, _, h⟩ := mem_map.mp (eq.symm ▸ mem_univ_val b); ⟨a, h⟩⟩⟩

end Multiset

/-- Auxiliary definition to show `exists_seq_of_forall_finset_exists`. -/
noncomputable def seqOfForallFinsetExistsAux {α : Type*} [DecidableEq α] (P : α → Prop)
    (r : α → α → Prop) (h : ∀ s : Finset α, ∃ y, (∀ x ∈ s, P x) → P y ∧ ∀ x ∈ s, r x y) : ℕ → α
  | n =>
    Classical.choose
      (h
        (Finset.image (fun i : Fin n => seqOfForallFinsetExistsAux P r h i)
          (Finset.univ : Finset (Fin n))))

/-- Induction principle to build a sequence, by adding one point at a time satisfying a given
relation with respect to all the previously chosen points.

More precisely, Assume that, for any finite set `s`, one can find another point satisfying
some relation `r` with respect to all the points in `s`. Then one may construct a
function `f : ℕ → α` such that `r (f m) (f n)` holds whenever `m < n`.
We also ensure that all constructed points satisfy a given predicate `P`. -/
```

-- snippet 35
```lean
-- Mathlib.Data.Fintype.Basic.truncSigmaOfExists (L212-L221)
def truncSigmaOfExists {α} [Fintype α] {P : α → Prop} [DecidablePred P] (h : ∃ a, P a) :
    Trunc (Σ' a, P a) :=
@truncOfNonemptyFintype (Σ' a, P a) ((Exists.elim h) fun a ha => ⟨⟨a, ha⟩⟩) _

end Trunc

namespace Multiset

variable [Fintype α] [Fintype β]
```

-- snippet 36
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_congr (L70-L72)
theorem prod_congr (f g : α → M) (h : ∀ a, f a = g a) : ∏ a, f a = ∏ a, g a :=
Finset.prod_congr rfl fun a _ha => h a
```

-- snippet 37
```lean
-- Mathlib.Data.Fintype.Basic.Unique (L115-L119)
instance Unique.fintype {α : Type*} [Unique α] : Fintype α :=
Fintype.ofSubsingleton default

/-- Short-circuit instance to decrease search for `Unique.fintype`,
since that relies on a subsingleton elimination for `Unique`. -/
```

-- snippet 38
```lean
-- Mathlib.Data.Fintype.BigOperators.prod_eq_one (L66-L68)
theorem prod_eq_one (f : α → M) (h : ∀ a, f a = 1) : ∏ a, f a = 1 :=
Finset.prod_eq_one fun a _ha => h a
```

-- snippet 39
```lean
-- Mathlib.Data.Fintype.Basic.PSigma (L173-L177)
instance PSigma.fintypePropLeft {α : Prop} {β : α → Type*} [Decidable α] [∀ a, Fintype (β a)] :
    Fintype (Σ' a, β a) :=
if h : α then Fintype.ofEquiv (β h) ⟨fun x => ⟨h, x⟩, PSigma.snd, fun _ => rfl, fun ⟨_, _⟩ => rfl⟩
  else ⟨∅, fun x => (h x.1).elim⟩
```

-- snippet 40
```lean
-- Mathlib.Data.Fintype.Basic.ULift (L160-L162)
instance ULift.fintype (α : Type*) [Fintype α] : Fintype (ULift α) :=
Fintype.ofEquiv _ Equiv.ulift.symm
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.Part).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem ne_none_iff {o : Part α} : o ≠ none ↔ ∃ x, o = some x
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.Part.toOption (L65-L67)
def toOption (o : Part α) [Decidable o.Dom] : Option α :=
if h : Dom o then some (o.get h) else none
```

-- snippet 2
```lean
-- Mathlib.Data.Part.ext' (L75-L80)
theorem ext' : ∀ {o p : Part α}, (o.Dom ↔ p.Dom) → (∀ h₁ h₂, o.get h₁ = p.get h₂) → o = p
  | ⟨od, o⟩, ⟨pd, p⟩, H1, H2 => by
    have t : od = pd := propext H1
cases t; rw [show o = p from funext fun p => H2 p p]

/-- `Part` eta expansion -/
```

-- snippet 3
```lean
-- Mathlib.Data.Part.eta (L82-L88)
theorem eta : ∀ o : Part α, (⟨o.Dom, fun h => o.get h⟩ : Part α) = o
  | ⟨_, _⟩ => rfl

/-- `a ∈ o` means that `o` is defined and equal to `a` -/
protected def Mem (o : Part α) (a : α) : Prop :=
∃ h, o.get h = a
```

-- snippet 4
```lean
-- Mathlib.Data.Part.mem_eq (L92-L94)
theorem mem_eq (a : α) (o : Part α) : (a ∈ o) = ∃ h, o.get h = a :=
rfl
```

-- snippet 5
```lean
-- Mathlib.Data.Part.dom_iff_mem (L95-L97)
theorem dom_iff_mem : ∀ {o : Part α}, o.Dom ↔ ∃ y, y ∈ o
  | ⟨_, f⟩ => ⟨fun h => ⟨f h, h, rfl⟩, fun ⟨_, h, rfl⟩ => h⟩
```

-- snippet 6
```lean
-- Mathlib.Data.Part.get_mem (L98-L100)
theorem get_mem {o : Part α} (h) : get o h ∈ o :=
⟨_, rfl⟩
```

-- snippet 7
```lean
-- Mathlib.Data.Part.mem_mk_iff (L102-L105)
theorem mem_mk_iff {p : Prop} {o : p → α} {a : α} : a ∈ Part.mk p o ↔ ∃ h, o h = a :=
Iff.rfl

/-- `Part` extensionality -/
```

-- snippet 8
```lean
-- Mathlib.Data.Part.ext (L107-L111)
theorem ext {o p : Part α} (H : ∀ a, a ∈ o ↔ a ∈ p) : o = p :=
(ext' ⟨fun h => ((H _).1 ⟨h, rfl⟩).fst, fun h => ((H _).2 ⟨h, rfl⟩).fst⟩) fun _ _ =>
    ((H _).2 ⟨_, rfl⟩).snd

/-- The `none` value in `Part` has a `False` domain and an empty function. -/
```

-- snippet 9
```lean
-- Mathlib.Data.Part.none (L112-L114)
def none : Part α :=
⟨False, False.rec⟩
```

-- snippet 10
```lean
-- Mathlib.Data.Part.notMem_none (L119-L122)
theorem notMem_none (a : α) : a ∉ @none α := fun h => h.fst
/-- The `some a` value in `Part` has a `True` domain and the
  function returns `a`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.Part.some (L123-L125)
def some (a : α) : Part α :=
⟨True, fun _ => a⟩
```

-- snippet 12
```lean
-- Mathlib.Data.Part.some_dom (L127-L129)
theorem some_dom (a : α) : (some a).Dom :=
trivial
```

-- snippet 13
```lean
-- Mathlib.Data.Part.mem_unique (L130-L132)
theorem mem_unique : ∀ {a b : α} {o : Part α}, a ∈ o → b ∈ o → a = b
  | _, _, ⟨_, _⟩, ⟨_, rfl⟩, ⟨_, rfl⟩ => rfl
```

-- snippet 14
```lean
-- Mathlib.Data.Part.mem_right_unique (L133-L135)
theorem mem_right_unique : ∀ {a : α} {o p : Part α}, a ∈ o → a ∈ p → o = p
  | _, _, _, ⟨ho, _⟩, ⟨hp, _⟩ => ext' (iff_of_true ho hp) (by simp [*])
```

-- snippet 15
```lean
-- Mathlib.Data.Part.Mem (L136-L138)
theorem Mem.left_unique : Relator.LeftUnique ((· ∈ ·) : α → Part α → Prop) := fun _ _ _ =>
mem_unique
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.Part).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem ne_none_iff {o : Part α} : o ≠ none ↔ ∃ x, o = some x
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.Part.toOption (L65-L67)
def toOption (o : Part α) [Decidable o.Dom] : Option α :=
if h : Dom o then some (o.get h) else none
```

-- snippet 2
```lean
-- Mathlib.Data.Part.ext' (L75-L80)
theorem ext' : ∀ {o p : Part α}, (o.Dom ↔ p.Dom) → (∀ h₁ h₂, o.get h₁ = p.get h₂) → o = p
  | ⟨od, o⟩, ⟨pd, p⟩, H1, H2 => by
    have t : od = pd := propext H1
cases t; rw [show o = p from funext fun p => H2 p p]

/-- `Part` eta expansion -/
```

-- snippet 3
```lean
-- Mathlib.Data.Part.eta (L82-L88)
theorem eta : ∀ o : Part α, (⟨o.Dom, fun h => o.get h⟩ : Part α) = o
  | ⟨_, _⟩ => rfl

/-- `a ∈ o` means that `o` is defined and equal to `a` -/
protected def Mem (o : Part α) (a : α) : Prop :=
∃ h, o.get h = a
```

-- snippet 4
```lean
-- Mathlib.Data.Part.mem_eq (L92-L94)
theorem mem_eq (a : α) (o : Part α) : (a ∈ o) = ∃ h, o.get h = a :=
rfl
```

-- snippet 5
```lean
-- Mathlib.Data.Part.dom_iff_mem (L95-L97)
theorem dom_iff_mem : ∀ {o : Part α}, o.Dom ↔ ∃ y, y ∈ o
  | ⟨_, f⟩ => ⟨fun h => ⟨f h, h, rfl⟩, fun ⟨_, h, rfl⟩ => h⟩
```

-- snippet 6
```lean
-- Mathlib.Data.Part.get_mem (L98-L100)
theorem get_mem {o : Part α} (h) : get o h ∈ o :=
⟨_, rfl⟩
```

-- snippet 7
```lean
-- Mathlib.Data.Part.mem_mk_iff (L102-L105)
theorem mem_mk_iff {p : Prop} {o : p → α} {a : α} : a ∈ Part.mk p o ↔ ∃ h, o h = a :=
Iff.rfl

/-- `Part` extensionality -/
```

-- snippet 8
```lean
-- Mathlib.Data.Part.ext (L107-L111)
theorem ext {o p : Part α} (H : ∀ a, a ∈ o ↔ a ∈ p) : o = p :=
(ext' ⟨fun h => ((H _).1 ⟨h, rfl⟩).fst, fun h => ((H _).2 ⟨h, rfl⟩).fst⟩) fun _ _ =>
    ((H _).2 ⟨_, rfl⟩).snd

/-- The `none` value in `Part` has a `False` domain and an empty function. -/
```

-- snippet 9
```lean
-- Mathlib.Data.Part.none (L112-L114)
def none : Part α :=
⟨False, False.rec⟩
```

-- snippet 10
```lean
-- Mathlib.Data.Part.notMem_none (L119-L122)
theorem notMem_none (a : α) : a ∉ @none α := fun h => h.fst
/-- The `some a` value in `Part` has a `True` domain and the
  function returns `a`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.Part.some (L123-L125)
def some (a : α) : Part α :=
⟨True, fun _ => a⟩
```

-- snippet 12
```lean
-- Mathlib.Data.Part.some_dom (L127-L129)
theorem some_dom (a : α) : (some a).Dom :=
trivial
```

-- snippet 13
```lean
-- Mathlib.Data.Part.mem_unique (L130-L132)
theorem mem_unique : ∀ {a b : α} {o : Part α}, a ∈ o → b ∈ o → a = b
  | _, _, ⟨_, _⟩, ⟨_, rfl⟩, ⟨_, rfl⟩ => rfl
```

-- snippet 14
```lean
-- Mathlib.Data.Part.mem_right_unique (L133-L135)
theorem mem_right_unique : ∀ {a : α} {o p : Part α}, a ∈ o → a ∈ p → o = p
  | _, _, _, ⟨ho, _⟩, ⟨hp, _⟩ => ext' (iff_of_true ho hp) (by simp [*])
```

-- snippet 15
```lean
-- Mathlib.Data.Part.Mem (L136-L138)
theorem Mem.left_unique : Relator.LeftUnique ((· ∈ ·) : α → Part α → Prop) := fun _ _ _ =>
mem_unique
```
[/INST]