l3lab/ntp-mathlib huggingface dataset:
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
  

Proof state:
V : Type u
G : SimpleGraph V
⊢ IsTree G ↔ Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
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_iff, 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]
theorem isTree_iff_existsUnique_path :
    G.IsTree ↔ Nonempty V ∧ ∀ v w : V, ∃! p : G.Walk v w, p.IsPath := by
  classical
  

Proof state:
V : Type u
G : SimpleGraph V
⊢ IsTree G ↔ Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
rw [IsTree_iff, isAcyclic_iff_path_unique]
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]
  

Proof state:
V : Type u
G : SimpleGraph V
⊢ (Connected G ∧ ∀ ⦃v w : V⦄ (p q : Path G v w), p = q) ↔ Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
constructor
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
  · 

Proof state:
case mp
V : Type u
G : SimpleGraph V
⊢ (Connected G ∧ ∀ ⦃v w : V⦄ (p q : Path G v w), p = q) → Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
rintro ⟨hc, hu⟩
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⟩
    

Proof state:
case mp.intro
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
⊢ Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
refine ⟨hc.nonempty, ?_⟩
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, ?_⟩
    

Proof state:
case mp.intro
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
⊢ ∀ (v w : V), ∃! p, IsPath p

Next tactic:
intro v w
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
    

Proof state:
case mp.intro
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
v w : V
⊢ ∃! p, IsPath p

Next tactic:
let q := (hc v w).some.toPath
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
    

Proof state:
case mp.intro
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
v w : V
q : Path G v w := toPath (Nonempty.some (_ : Reachable G v w))
⊢ ∃! p, IsPath p

Next tactic:
use q
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
    

Proof state:
case h
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
v w : V
q : Path G v w := toPath (Nonempty.some (_ : Reachable G v w))
⊢ (fun p => IsPath p) ↑q ∧ ∀ (y : Walk G v w), (fun p => IsPath p) y → y = ↑q

Next tactic:
simp only [true_and_iff, Path.isPath]
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_iff, Path.isPath]
    

Proof state:
case h
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
v w : V
q : Path G v w := toPath (Nonempty.some (_ : Reachable G v w))
⊢ ∀ (y : Walk G v w), IsPath y → y = ↑(toPath (Nonempty.some (_ : Reachable G v w)))

Next tactic:
intro p hp
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_iff, Path.isPath]
    intro p hp
    

Proof state:
case h
V : Type u
G : SimpleGraph V
hc : Connected G
hu : ∀ ⦃v w : V⦄ (p q : Path G v w), p = q
v w : V
q : Path G v w := toPath (Nonempty.some (_ : Reachable G v w))
p : Walk G v w
hp : IsPath p
⊢ p = ↑(toPath (Nonempty.some (_ : Reachable G v w)))

Next tactic:
specialize hu ⟨p, hp⟩ q
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_iff, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    

Proof state:
case h
V : Type u
G : SimpleGraph V
hc : Connected G
v w : V
q : Path G v w := toPath (Nonempty.some (_ : Reachable G v w))
p : Walk G v w
hp : IsPath p
hu : { val := p, property := hp } = q
⊢ p = ↑(toPath (Nonempty.some (_ : Reachable G v w)))

Next tactic:
exact Subtype.ext_iff.mp hu
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_iff, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · 

Proof state:
case mpr
V : Type u
G : SimpleGraph V
⊢ (Nonempty V ∧ ∀ (v w : V), ∃! p, IsPath p) → Connected G ∧ ∀ ⦃v w : V⦄ (p q : Path G v w), p = q

Next tactic:
rintro ⟨hV, h⟩
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_iff, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    

Proof state:
case mpr.intro
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
⊢ Connected G ∧ ∀ ⦃v w : V⦄ (p q : Path G v w), p = q

Next tactic:
refine ⟨Connected.mk ?_, ?_⟩
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_iff, Path.isPath]
    intro p hp
    specialize hu ⟨p, hp⟩ q
    exact Subtype.ext_iff.mp hu
  · rintro ⟨hV, h⟩
    refine ⟨Connected.mk ?_, ?_⟩
    · 

Proof state:
case mpr.intro.refine_1
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
⊢ Preconnected G

Next tactic:
intro v w
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_iff, 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
      

Proof state:
case mpr.intro.refine_1
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
v w : V
⊢ Reachable G v w

Next tactic:
obtain ⟨p, _⟩ := h v w
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_iff, 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
      

Proof state:
case mpr.intro.refine_1.intro
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
v w : V
p : Walk G v w
h✝ : (fun p => IsPath p) p ∧ ∀ (y : Walk G v w), (fun p => IsPath p) y → y = p
⊢ Reachable G v w

Next tactic:
exact p.reachable
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_iff, 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
    · 

Proof state:
case mpr.intro.refine_2
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
⊢ ∀ ⦃v w : V⦄ (p q : Path G v w), p = q

Next tactic:
rintro v w ⟨p, hp⟩ ⟨q, hq⟩
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_iff, 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⟩
      

Proof state:
case mpr.intro.refine_2.mk.mk
V : Type u
G : SimpleGraph V
hV : Nonempty V
h : ∀ (v w : V), ∃! p, IsPath p
v w : V
p : Walk G v w
hp : IsPath p
q : Walk G v w
hq : IsPath q
⊢ { val := p, property := hp } = { val := q, property := hq }

Next tactic:
simp only [ExistsUnique.unique (h v w) hp hq]
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
⊢ Finset.card (edgeFinset G) + 1 = Fintype.card V

Next tactic:
have := hG.isConnected.nonempty
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this : Nonempty V
⊢ Finset.card (edgeFinset G) + 1 = Fintype.card V

Next tactic:
inhabit V
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this : Nonempty V
inhabited_h : Inhabited V
⊢ Finset.card (edgeFinset G) + 1 = Fintype.card V

Next tactic:
classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
  case notNil => exact not_nil_of_ne (by simpa using hw)
  case memEdges => simp
  case inj =>
    intros a b ha hb h
    wlog h' : (f a).length ≤ (f b).length generalizing a b
    · exact Eq.symm (this _ _ hb ha h.symm (le_of_not_le h'))
    rw [dart_edge_eq_iff] at h
    obtain (h | h) := h
    · exact (congrArg (·.fst) h)
    · have h1 : ((f a).firstDart <| not_nil_of_ne (by simpa using ha)).snd = b :=
        congrArg (·.snd) h
      have h3 := congrArg length (hf' _ (((f _).tail _).copy h1 rfl) ?_)
      rw [length_copy, ← add_left_inj 1, length_tail_add_one] at h3
      · exfalso
        linarith
      · simp only [ne_eq, eq_mp_eq_cast, id_eq, isPath_copy]
        exact (hf _).tail _
  case surj =>
    simp only [mem_edgeFinset, Finset.mem_compl, Finset.mem_singleton, Sym2.forall, mem_edgeSet]
    intros x y h
    wlog h' : (f x).length ≤ (f y).length generalizing x y
    · rw [Sym2.eq_swap]
      exact this y x h.symm (le_of_not_le h')
    refine ⟨y, ?_, dart_edge_eq_mk'_iff.2 <| Or.inr ?_⟩
    · rintro rfl
      rw [← hf' _ nil IsPath.nil, length_nil,
          ← hf' _ (.cons h .nil) (IsPath.nil.cons <| by simpa using h.ne),
          length_cons, length_nil] at h'
      simp [le_zero_iff, Nat.one_ne_zero] at h'
    rw [← hf' _ (.cons h.symm (f x)) ((cons_isPath_iff _ _).2 ⟨hf _, fun hy => ?contra⟩)]
    rfl
    case contra =>
      suffices : (f x).takeUntil y hy = .cons h .nil
      · rw [← take_spec _ hy] at h'
        simp [this, hf' _ _ ((hf _).dropUntil hy)] at h'
      refine (hG.existsUnique_path _ _).unique ((hf _).takeUntil _) ?_
      simp [h.ne]
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this : Nonempty V
inhabited_h : Inhabited V
⊢ Finset.card (edgeFinset G) + 1 = Fintype.card V

Next tactic:
have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this : Nonempty V
inhabited_h : Inhabited V
⊢ Finset.card {default}ᶜ + 1 = Fintype.card V

Next tactic:
rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
⊢ Finset.card (edgeFinset G) + 1 = Fintype.card V

Next tactic:
rw [← this, add_left_inj]
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
⊢ Finset.card (edgeFinset G) = Finset.card {default}ᶜ

Next tactic:
choose f hf hf' using (hG.existsUnique_path · default)
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
⊢ Finset.card (edgeFinset G) = Finset.card {default}ᶜ

Next tactic:
refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
  

Proof state:
case notNil
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
w : V
hw : w ∈ {default}ᶜ
⊢ ¬Nil (f w)
case memEdges
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
a : V
ha : a ∈ {default}ᶜ
⊢ (fun w hw => Dart.edge (firstDart (f w) (_ : ¬Nil (f w)))) a ha ∈ edgeFinset G
case inj
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
⊢ ∀ (a b : V) (ha : a ∈ {default}ᶜ) (hb : b ∈ {default}ᶜ),
    (fun w hw => Dart.edge (firstDart (f w) (_ : ¬Nil (f w)))) a ha =
        (fun w hw => Dart.edge (firstDart (f w) (_ : ¬Nil (f w)))) b hb →
      a = b
case surj
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
⊢ ∀ b ∈ edgeFinset G, ∃ a, ∃ (ha : a ∈ {default}ᶜ), (fun w hw => Dart.edge (firstDart (f w) (_ : ¬Nil (f w)))) a ha = b

Next tactic:
case notNil => exact not_nil_of_ne (by simpa using hw)
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
w : V
hw : w ∈ {default}ᶜ
⊢ ¬Nil (f w)

Next tactic:
case notNil => exact not_nil_of_ne (by simpa using hw)
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
  case notNil => 

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
w : V
hw : w ∈ {default}ᶜ
⊢ ¬Nil (f w)

Next tactic:
exact not_nil_of_ne (by simpa using hw)
lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) :
    Finset.card G.edgeFinset + 1 = Fintype.card V := by
  have := hG.isConnected.nonempty
  inhabit V
  classical
  have : Finset.card ({default} : Finset V)ᶜ + 1 = Fintype.card V := by
    rw [Finset.card_compl, Finset.card_singleton, Nat.sub_add_cancel Fintype.card_pos]
  rw [← this, add_left_inj]
  choose f hf hf' using (hG.existsUnique_path · default)
  refine Eq.symm <| Finset.card_congr
          (fun w hw => ((f w).firstDart <| ?notNil).edge)
          (fun a ha => ?memEdges) ?inj ?surj
  case notNil => exact not_nil_of_ne (by 

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : Fintype ↑(edgeSet G)
hG : IsTree G
this✝ : Nonempty V
inhabited_h : Inhabited V
this : Finset.card {default}ᶜ + 1 = Fintype.card V
f : (x : V) → Walk G x default
hf : ∀ (x : V), (fun p => IsPath p) (f x)
hf' : ∀ (x : V) (y : Walk G x default), (fun p => IsPath p) y → y = f x
w : V
hw : w ∈ {default}ᶜ
⊢ w ≠ default

Next tactic:
simpa using hw