l3lab/ntp-mathlib huggingface dataset:
/-- The function `f x / g x` is discontinuous when `g x = 0`. However, under appropriate
conditions, `h x (f x / g x)` is still continuous.  The condition is that if `g a = 0` then `h x y`
must tend to `h a 0` when `x` tends to `a`, with no information about `y`. This is represented by
the `⊤` filter.  Note: `tendsto_prod_top_iff` characterizes this convergence in uniform spaces.  See
also `Filter.prod_top` and `Filter.mem_prod_top`. -/
theorem ContinuousAt.comp_div_cases {f g : α → G₀} (h : α → G₀ → β) (hf : ContinuousAt f a)
    (hg : ContinuousAt g a) (hh : g a ≠ 0 → ContinuousAt (↿h) (a, f a / g a))
    (h2h : g a = 0 → Tendsto (↿h) (𝓝 a ×ˢ ⊤) (𝓝 (h a 0))) :
    ContinuousAt (fun x => h x (f x / g x)) a := by
  show ContinuousAt (↿h ∘ fun x => (x, f x / g x)) a
  by_cases hga : g a = 0
  · rw [ContinuousAt]
    simp_rw [comp_apply, hga, div_zero]
    exact (h2h hga).comp (continuousAt_id.prod_mk tendsto_top)
  · 

Proof state:
case neg
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝⁵ : GroupWithZero G₀
inst✝⁴ : TopologicalSpace G₀
inst✝³ : HasContinuousInv₀ G₀
inst✝² : ContinuousMul G₀
f✝ g✝ : α → G₀
inst✝¹ : TopologicalSpace α
inst✝ : TopologicalSpace β
s : Set α
a : α
f g : α → G₀
h : α → G₀ → β
hf : ContinuousAt f a
hg : ContinuousAt g a
hh : g a ≠ 0 → ContinuousAt (↿h) (a, f a / g a)
h2h : g a = 0 → Tendsto (↿h) (𝓝 a ×ˢ ⊤) (𝓝 (h a 0))
hga : ¬g a = 0
⊢ ContinuousAt (↿h ∘ fun x => (x, f x / g x)) a

Next tactic:
exact ContinuousAt.comp (hh hga) (continuousAt_id.prod (hf.div hg hga))
theorem map_mul_left_nhds_one₀ (ha : a ≠ 0) : map (a * ·) (𝓝 1) = 𝓝 (a) := by
  

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
ha : a ≠ 0
⊢ map (fun x => a * x) (𝓝 1) = 𝓝 a

Next tactic:
rw [map_mul_left_nhds₀ ha, mul_one]
theorem map_mul_right_nhds_one₀ (ha : a ≠ 0) : map (· * a) (𝓝 1) = 𝓝 (a) := by
  

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
ha : a ≠ 0
⊢ map (fun x => x * a) (𝓝 1) = 𝓝 a

Next tactic:
rw [map_mul_right_nhds₀ ha, one_mul]
theorem nhds_translation_mul_inv₀ (ha : a ≠ 0) : comap (· * a⁻¹) (𝓝 1) = 𝓝 a :=
  ((Homeomorph.mulRight₀ a ha).symm.comap_nhds_eq 1).trans <| by 

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
ha : a ≠ 0
⊢ 𝓝 ((Homeomorph.symm (Homeomorph.symm (Homeomorph.mulRight₀ a ha))) 1) = 𝓝 a

Next tactic:
simp
/-- If a group with zero has continuous multiplication and `fun x ↦ x⁻¹` is continuous at one,
then it is continuous at any unit. -/
theorem HasContinuousInv₀.of_nhds_one (h : Tendsto Inv.inv (𝓝 (1 : G₀)) (𝓝 1)) :
    HasContinuousInv₀ G₀ where
  continuousAt_inv₀ x hx := by
    

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
h : Tendsto Inv.inv (𝓝 1) (𝓝 1)
x : G₀
hx : x ≠ 0
⊢ ContinuousAt Inv.inv x

Next tactic:
have hx' := inv_ne_zero hx
/-- If a group with zero has continuous multiplication and `fun x ↦ x⁻¹` is continuous at one,
then it is continuous at any unit. -/
theorem HasContinuousInv₀.of_nhds_one (h : Tendsto Inv.inv (𝓝 (1 : G₀)) (𝓝 1)) :
    HasContinuousInv₀ G₀ where
  continuousAt_inv₀ x hx := by
    have hx' := inv_ne_zero hx
    

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
h : Tendsto Inv.inv (𝓝 1) (𝓝 1)
x : G₀
hx : x ≠ 0
hx' : x⁻¹ ≠ 0
⊢ ContinuousAt Inv.inv x

Next tactic:
rw [ContinuousAt, ← map_mul_left_nhds_one₀ hx, ← nhds_translation_mul_inv₀ hx',
      tendsto_map'_iff, tendsto_comap_iff]
/-- If a group with zero has continuous multiplication and `fun x ↦ x⁻¹` is continuous at one,
then it is continuous at any unit. -/
theorem HasContinuousInv₀.of_nhds_one (h : Tendsto Inv.inv (𝓝 (1 : G₀)) (𝓝 1)) :
    HasContinuousInv₀ G₀ where
  continuousAt_inv₀ x hx := by
    have hx' := inv_ne_zero hx
    rw [ContinuousAt, ← map_mul_left_nhds_one₀ hx, ← nhds_translation_mul_inv₀ hx',
      tendsto_map'_iff, tendsto_comap_iff]
    

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝² : TopologicalSpace G₀
inst✝¹ : GroupWithZero G₀
inst✝ : ContinuousMul G₀
a : G₀
h : Tendsto Inv.inv (𝓝 1) (𝓝 1)
x : G₀
hx : x ≠ 0
hx' : x⁻¹ ≠ 0
⊢ Tendsto ((fun x_1 => x_1 * x⁻¹⁻¹) ∘ Inv.inv ∘ fun x_1 => x * x_1) (𝓝 1) (𝓝 1)

Next tactic:
simpa only [(· ∘ ·), mul_inv_rev, mul_inv_cancel_right₀ hx']
theorem continuousAt_zpow₀ (x : G₀) (m : ℤ) (h : x ≠ 0 ∨ 0 ≤ m) :
    ContinuousAt (fun x => x ^ m) x := by
  

Proof state:
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝³ : GroupWithZero G₀
inst✝² : TopologicalSpace G₀
inst✝¹ : HasContinuousInv₀ G₀
inst✝ : ContinuousMul G₀
x : G₀
m : ℤ
h : x ≠ 0 ∨ 0 ≤ m
⊢ ContinuousAt (fun x => x ^ m) x

Next tactic:
cases' m with m m
theorem continuousAt_zpow₀ (x : G₀) (m : ℤ) (h : x ≠ 0 ∨ 0 ≤ m) :
    ContinuousAt (fun x => x ^ m) x := by
  cases' m with m m
  · 

Proof state:
case ofNat
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝³ : GroupWithZero G₀
inst✝² : TopologicalSpace G₀
inst✝¹ : HasContinuousInv₀ G₀
inst✝ : ContinuousMul G₀
x : G₀
m : ℕ
h : x ≠ 0 ∨ 0 ≤ Int.ofNat m
⊢ ContinuousAt (fun x => x ^ Int.ofNat m) x

Next tactic:
simpa only [Int.ofNat_eq_coe, zpow_coe_nat] using continuousAt_pow x m
theorem continuousAt_zpow₀ (x : G₀) (m : ℤ) (h : x ≠ 0 ∨ 0 ≤ m) :
    ContinuousAt (fun x => x ^ m) x := by
  cases' m with m m
  · simpa only [Int.ofNat_eq_coe, zpow_coe_nat] using continuousAt_pow x m
  · 

Proof state:
case negSucc
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝³ : GroupWithZero G₀
inst✝² : TopologicalSpace G₀
inst✝¹ : HasContinuousInv₀ G₀
inst✝ : ContinuousMul G₀
x : G₀
m : ℕ
h : x ≠ 0 ∨ 0 ≤ Int.negSucc m
⊢ ContinuousAt (fun x => x ^ Int.negSucc m) x

Next tactic:
simp only [zpow_negSucc]
theorem continuousAt_zpow₀ (x : G₀) (m : ℤ) (h : x ≠ 0 ∨ 0 ≤ m) :
    ContinuousAt (fun x => x ^ m) x := by
  cases' m with m m
  · simpa only [Int.ofNat_eq_coe, zpow_coe_nat] using continuousAt_pow x m
  · simp only [zpow_negSucc]
    

Proof state:
case negSucc
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝³ : GroupWithZero G₀
inst✝² : TopologicalSpace G₀
inst✝¹ : HasContinuousInv₀ G₀
inst✝ : ContinuousMul G₀
x : G₀
m : ℕ
h : x ≠ 0 ∨ 0 ≤ Int.negSucc m
⊢ ContinuousAt (fun x => (x ^ (m + 1))⁻¹) x

Next tactic:
have hx : x ≠ 0 := h.resolve_right (Int.negSucc_lt_zero m).not_le
theorem continuousAt_zpow₀ (x : G₀) (m : ℤ) (h : x ≠ 0 ∨ 0 ≤ m) :
    ContinuousAt (fun x => x ^ m) x := by
  cases' m with m m
  · simpa only [Int.ofNat_eq_coe, zpow_coe_nat] using continuousAt_pow x m
  · simp only [zpow_negSucc]
    have hx : x ≠ 0 := h.resolve_right (Int.negSucc_lt_zero m).not_le
    

Proof state:
case negSucc
α : Type u_1
β : Type u_2
G₀ : Type u_3
inst✝³ : GroupWithZero G₀
inst✝² : TopologicalSpace G₀
inst✝¹ : HasContinuousInv₀ G₀
inst✝ : ContinuousMul G₀
x : G₀
m : ℕ
h : x ≠ 0 ∨ 0 ≤ Int.negSucc m
hx : x ≠ 0
⊢ ContinuousAt (fun x => (x ^ (m + 1))⁻¹) x

Next tactic:
exact (continuousAt_pow x (m + 1)).inv₀ (pow_ne_zero _ hx)
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
⊢ filter (fun d => d.toProd.1 = v) univ = image (dartOfNeighborSet G v) univ

Next tactic:
ext d
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  

Proof state:
case a
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
d : Dart G
⊢ d ∈ filter (fun d => d.toProd.1 = v) univ ↔ d ∈ image (dartOfNeighborSet G v) univ

Next tactic:
simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  

Proof state:
case a
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
d : Dart G
⊢ d.toProd.1 = v ↔ ∃ x, ∃ (h : x ∈ neighborSet G v), dartOfNeighborSet G v { val := x, property := h } = d

Next tactic:
constructor
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · 

Proof state:
case a.mp
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
d : Dart G
⊢ d.toProd.1 = v → ∃ x, ∃ (h : x ∈ neighborSet G v), dartOfNeighborSet G v { val := x, property := h } = d

Next tactic:
rintro rfl
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    

Proof state:
case a.mp
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
⊢ ∃ x, ∃ (h : x ∈ neighborSet G d.toProd.1), dartOfNeighborSet G d.toProd.1 { val := x, property := h } = d

Next tactic:
exact ⟨_, d.is_adj, by ext <;> rfl⟩
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    exact ⟨_, d.is_adj, by 

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
⊢ dartOfNeighborSet G d.toProd.1 { val := d.toProd.2, property := (_ : Adj G d.toProd.1 d.toProd.2) } = d

Next tactic:
ext
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    exact ⟨_, d.is_adj, by ext <;> 

Proof state:
case h.a
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
⊢ (dartOfNeighborSet G d.toProd.1 { val := d.toProd.2, property := (_ : Adj G d.toProd.1 d.toProd.2) }).toProd.1 =
    d.toProd.1

Next tactic:
rfl
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    exact ⟨_, d.is_adj, by ext <;> 

Proof state:
case h.a
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
⊢ (dartOfNeighborSet G d.toProd.1 { val := d.toProd.2, property := (_ : Adj G d.toProd.1 d.toProd.2) }).toProd.2 =
    d.toProd.2

Next tactic:
rfl
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    exact ⟨_, d.is_adj, by ext <;> rfl⟩
  · 

Proof state:
case a.mpr
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
d : Dart G
⊢ (∃ x, ∃ (h : x ∈ neighborSet G v), dartOfNeighborSet G v { val := x, property := h } = d) → d.toProd.1 = v

Next tactic:
rintro ⟨e, he, rfl⟩
theorem dart_fst_fiber [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v) = univ.image (G.dartOfNeighborSet v) := by
  ext d
  simp only [mem_image, true_and_iff, mem_filter, SetCoe.exists, mem_univ, exists_prop_of_true]
  constructor
  · rintro rfl
    exact ⟨_, d.is_adj, by ext <;> rfl⟩
  · rintro ⟨e, he, rfl⟩
    

Proof state:
case a.mpr.intro.intro
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v e : V
he : e ∈ neighborSet G v
⊢ (dartOfNeighborSet G v { val := e, property := he }).toProd.1 = v

Next tactic:
rfl
theorem dart_fst_fiber_card_eq_degree [DecidableEq V] (v : V) :
    (univ.filter fun d : G.Dart => d.fst = v).card = G.degree v := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
v : V
⊢ card (filter (fun d => d.toProd.1 = v) univ) = degree G v

Next tactic:
simpa only [dart_fst_fiber, Finset.card_univ, card_neighborSet_eq_degree] using
    card_image_of_injective univ (G.dartOfNeighborSet_injective v)
theorem dart_card_eq_sum_degrees : Fintype.card G.Dart = ∑ v, G.degree v := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝² : Fintype V
inst✝¹ : DecidableRel G.Adj
inst✝ : Fintype (Sym2 V)
⊢ Fintype.card (Dart G) = ∑ v : V, degree G v

Next tactic:
haveI := Classical.decEq V
theorem dart_card_eq_sum_degrees : Fintype.card G.Dart = ∑ v, G.degree v := by
  haveI := Classical.decEq V
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝² : Fintype V
inst✝¹ : DecidableRel G.Adj
inst✝ : Fintype (Sym2 V)
this : DecidableEq V
⊢ Fintype.card (Dart G) = ∑ v : V, degree G v

Next tactic:
simp only [← card_univ, ← dart_fst_fiber_card_eq_degree]
theorem dart_card_eq_sum_degrees : Fintype.card G.Dart = ∑ v, G.degree v := by
  haveI := Classical.decEq V
  simp only [← card_univ, ← dart_fst_fiber_card_eq_degree]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝² : Fintype V
inst✝¹ : DecidableRel G.Adj
inst✝ : Fintype (Sym2 V)
this : DecidableEq V
⊢ card univ = ∑ x : V, card (filter (fun d => d.toProd.1 = x) univ)

Next tactic:
exact card_eq_sum_card_fiberwise (by simp)
theorem dart_card_eq_sum_degrees : Fintype.card G.Dart = ∑ v, G.degree v := by
  haveI := Classical.decEq V
  simp only [← card_univ, ← dart_fst_fiber_card_eq_degree]
  exact card_eq_sum_card_fiberwise (by 

Proof state:
V : Type u
G : SimpleGraph V
inst✝² : Fintype V
inst✝¹ : DecidableRel G.Adj
inst✝ : Fintype (Sym2 V)
this : DecidableEq V
⊢ ∀ x ∈ univ, x.toProd.1 ∈ univ

Next tactic:
simp
theorem Dart.edge_fiber (d : G.Dart) :
    (univ.filter fun d' : G.Dart => d'.edge = d.edge) = {d, d.symm} :=
  Finset.ext fun d' => by 

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d d' : Dart G
⊢ d' ∈ filter (fun d' => edge d' = edge d) univ ↔ d' ∈ {d, symm d}

Next tactic:
simpa using dart_edge_eq_iff d' d
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h : e ∈ edgeSet G
⊢ card (filter (fun d => Dart.edge d = e) univ) = 2

Next tactic:
refine' Sym2.ind (fun v w h => _) e h
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  refine' Sym2.ind (fun v w h => _) e h
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h✝ : e ∈ edgeSet G
v w : V
h : ⟦(v, w)⟧ ∈ edgeSet G
⊢ card (filter (fun d => Dart.edge d = ⟦(v, w)⟧) univ) = 2

Next tactic:
let d : G.Dart := ⟨(v, w), h⟩
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  refine' Sym2.ind (fun v w h => _) e h
  let d : G.Dart := ⟨(v, w), h⟩
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h✝ : e ∈ edgeSet G
v w : V
h : ⟦(v, w)⟧ ∈ edgeSet G
d : Dart G := { toProd := (v, w), is_adj := h }
⊢ card (filter (fun d => Dart.edge d = ⟦(v, w)⟧) univ) = 2

Next tactic:
convert congr_arg card d.edge_fiber
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  refine' Sym2.ind (fun v w h => _) e h
  let d : G.Dart := ⟨(v, w), h⟩
  convert congr_arg card d.edge_fiber
  

Proof state:
case h.e'_3
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h✝ : e ∈ edgeSet G
v w : V
h : ⟦(v, w)⟧ ∈ edgeSet G
d : Dart G := { toProd := (v, w), is_adj := h }
⊢ 2 = card {d, Dart.symm d}

Next tactic:
rw [card_insert_of_not_mem, card_singleton]
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  refine' Sym2.ind (fun v w h => _) e h
  let d : G.Dart := ⟨(v, w), h⟩
  convert congr_arg card d.edge_fiber
  rw [card_insert_of_not_mem, card_singleton]
  

Proof state:
case h.e'_3
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h✝ : e ∈ edgeSet G
v w : V
h : ⟦(v, w)⟧ ∈ edgeSet G
d : Dart G := { toProd := (v, w), is_adj := h }
⊢ d ∉ {Dart.symm d}

Next tactic:
rw [mem_singleton]
theorem dart_edge_fiber_card (e : Sym2 V) (h : e ∈ G.edgeSet) :
    (univ.filter fun d : G.Dart => d.edge = e).card = 2 := by
  refine' Sym2.ind (fun v w h => _) e h
  let d : G.Dart := ⟨(v, w), h⟩
  convert congr_arg card d.edge_fiber
  rw [card_insert_of_not_mem, card_singleton]
  rw [mem_singleton]
  

Proof state:
case h.e'_3
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h✝ : e ∈ edgeSet G
v w : V
h : ⟦(v, w)⟧ ∈ edgeSet G
d : Dart G := { toProd := (v, w), is_adj := h }
⊢ ¬d = Dart.symm d

Next tactic:
exact d.symm_ne.symm
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
⊢ Fintype.card (Dart G) = 2 * card (edgeFinset G)

Next tactic:
rw [← card_univ]
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
⊢ card univ = 2 * card (edgeFinset G)

Next tactic:
rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; apply Dart.edge_mem]
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by 

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
_h : d ∈ univ
⊢ Dart.edge d ∈ edgeFinset G

Next tactic:
rw [mem_edgeFinset]
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; 

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
d : Dart G
_h : d ∈ univ
⊢ Dart.edge d ∈ edgeSet G

Next tactic:
apply Dart.edge_mem
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; apply Dart.edge_mem]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
⊢ ∑ a in edgeFinset G, card (filter (fun x => Dart.edge x = a) univ) = 2 * card (edgeFinset G)

Next tactic:
rw [← mul_comm, sum_const_nat]
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; apply Dart.edge_mem]
  rw [← mul_comm, sum_const_nat]
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
⊢ ∀ x ∈ edgeFinset G, card (filter (fun x_1 => Dart.edge x_1 = x) univ) = 2

Next tactic:
intro e h
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; apply Dart.edge_mem]
  rw [← mul_comm, sum_const_nat]
  intro e h
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h : e ∈ edgeFinset G
⊢ card (filter (fun x => Dart.edge x = e) univ) = 2

Next tactic:
apply G.dart_edge_fiber_card e
theorem dart_card_eq_twice_card_edges : Fintype.card G.Dart = 2 * G.edgeFinset.card := by
  rw [← card_univ]
  rw [@card_eq_sum_card_fiberwise _ _ _ Dart.edge _ G.edgeFinset fun d _h =>
      by rw [mem_edgeFinset]; apply Dart.edge_mem]
  rw [← mul_comm, sum_const_nat]
  intro e h
  apply G.dart_edge_fiber_card e
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝³ : Fintype V
inst✝² : DecidableRel G.Adj
inst✝¹ : Fintype (Sym2 V)
inst✝ : DecidableEq V
e : Sym2 V
h : e ∈ edgeFinset G
⊢ e ∈ edgeSet G

Next tactic:
rwa [← mem_edgeFinset]
/-- The handshaking lemma.  See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/
theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] :
    Even (univ.filter fun v => Odd (G.degree v)).card := by
  

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : DecidableRel G.Adj
⊢ Even (card (filter (fun v => Odd (degree G v)) univ))

Next tactic:
classical
    have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges
    simp only [ZMod.nat_cast_self, zero_mul, Nat.cast_mul] at h
    rw [Nat.cast_sum, ← sum_filter_ne_zero] at h
    rw [@sum_congr _ _ _ _ (fun v => (G.degree v : ZMod 2)) (fun _v => (1 : ZMod 2)) _ rfl] at h
    · simp only [filter_congr, mul_one, nsmul_eq_mul, sum_const, Ne.def] at h
      rw [← ZMod.eq_zero_iff_even]
      convert h
      exact ZMod.ne_zero_iff_odd.symm
    · intro v
      simp only [true_and_iff, mem_filter, mem_univ, Ne.def]
      rw [ZMod.eq_zero_iff_even, ZMod.eq_one_iff_odd, Nat.odd_iff_not_even, imp_self]
      trivial
/-- The handshaking lemma.  See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/
theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] :
    Even (univ.filter fun v => Odd (G.degree v)).card := by
  classical
    

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : DecidableRel G.Adj
⊢ Even (card (filter (fun v => Odd (degree G v)) univ))

Next tactic:
have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges
/-- The handshaking lemma.  See also `SimpleGraph.sum_degrees_eq_twice_card_edges`. -/
theorem even_card_odd_degree_vertices [Fintype V] [DecidableRel G.Adj] :
    Even (univ.filter fun v => Odd (G.degree v)).card := by
  classical
    have h := congr_arg (fun n => ↑n : ℕ → ZMod 2) G.sum_degrees_eq_twice_card_edges
    

Proof state:
V : Type u
G : SimpleGraph V
inst✝¹ : Fintype V
inst✝ : DecidableRel G.Adj
h : (fun n => ↑n) (∑ v : V, degree G v) = (fun n => ↑n) (2 * card (edgeFinset G))
⊢ Even (card (filter (fun v => Odd (degree G v)) univ))

Next tactic:
simp only [ZMod.nat_cast_self, zero_mul, Nat.cast_mul] at h