[GOAL]
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
⊢ CutExpand r ≤ InvImage (Finsupp.Lex (rᶜ ⊓ fun x x_1 => x ≠ x_1) fun x x_1 => x < x_1) ↑toFinsupp
[PROOFSTEP]
rintro s t ⟨u, a, hr, he⟩
[GOAL]
case intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ u → r a' a
he : s + {a} = t + u
⊢ InvImage (Finsupp.Lex (rᶜ ⊓ fun x x_1 => x ≠ x_1) fun x x_1 => x < x_1) (↑toFinsupp) s t
[PROOFSTEP]
replace hr := fun a' ↦ mt (hr a')
[GOAL]
case intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
⊢ InvImage (Finsupp.Lex (rᶜ ⊓ fun x x_1 => x ≠ x_1) fun x x_1 => x < x_1) (↑toFinsupp) s t
[PROOFSTEP]
classical
refine ⟨a, fun b h ↦ ?_, ?_⟩ <;> simp_rw [toFinsupp_apply]
· apply_fun count b at he
  simpa only [count_add, count_singleton, if_neg h.2, add_zero, count_eq_zero.2 (hr b h.1)] using he
· apply_fun count a at he
  simp only [count_add, count_singleton_self, count_eq_zero.2 (hr _ (irrefl_of r a)), add_zero] at he
  exact he ▸ Nat.lt_succ_self _
[GOAL]
case intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
⊢ InvImage (Finsupp.Lex (rᶜ ⊓ fun x x_1 => x ≠ x_1) fun x x_1 => x < x_1) (↑toFinsupp) s t
[PROOFSTEP]
refine ⟨a, fun b h ↦ ?_, ?_⟩
[GOAL]
case intro.intro.intro.refine_1
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
b : α
h : (rᶜ ⊓ fun x x_1 => x ≠ x_1) b a
⊢ ↑(↑toFinsupp s) b = ↑(↑toFinsupp t) b
[PROOFSTEP]
simp_rw [toFinsupp_apply]
[GOAL]
case intro.intro.intro.refine_2
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
⊢ (fun {i} x x_1 => x < x_1) (↑(↑toFinsupp s) a) (↑(↑toFinsupp t) a)
[PROOFSTEP]
simp_rw [toFinsupp_apply]
[GOAL]
case intro.intro.intro.refine_1
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
b : α
h : (rᶜ ⊓ fun x x_1 => x ≠ x_1) b a
⊢ count b s = count b t
[PROOFSTEP]
apply_fun count b at he
[GOAL]
case intro.intro.intro.refine_1
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
b : α
h : (rᶜ ⊓ fun x x_1 => x ≠ x_1) b a
he : count b (s + {a}) = count b (t + u)
⊢ count b s = count b t
[PROOFSTEP]
simpa only [count_add, count_singleton, if_neg h.2, add_zero, count_eq_zero.2 (hr b h.1)] using he
[GOAL]
case intro.intro.intro.refine_2
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
he : s + {a} = t + u
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
⊢ count a s < count a t
[PROOFSTEP]
apply_fun count a at he
[GOAL]
case intro.intro.intro.refine_2
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
he : count a (s + {a}) = count a (t + u)
⊢ count a s < count a t
[PROOFSTEP]
simp only [count_add, count_singleton_self, count_eq_zero.2 (hr _ (irrefl_of r a)), add_zero] at he
[GOAL]
case intro.intro.intro.refine_2
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t u : Multiset α
a : α
hr : ∀ (a' : α), ¬r a' a → ¬a' ∈ u
he : count a s + 1 = count a t
⊢ count a s < count a t
[PROOFSTEP]
exact he ▸ Nat.lt_succ_self _
[GOAL]
α : Type u_1
r : α → α → Prop
x' x : α
h✝ : r x' x
a : α
h : a ∈ {x'}
⊢ r a x
[PROOFSTEP]
rwa [mem_singleton.1 h]
[GOAL]
α : Type u_1
r : α → α → Prop
t u s x✝¹ : Multiset α
x✝ : α
⊢ s + t + {x✝} = s + u + x✝¹ ↔ t + {x✝} = u + x✝¹
[PROOFSTEP]
rw [add_assoc, add_assoc, add_left_cancel_iff]
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s' s : Multiset α
⊢ CutExpand r s' s ↔ ∃ t a, (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ s' = erase s a + t
[PROOFSTEP]
simp_rw [CutExpand, add_singleton_eq_iff]
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s' s : Multiset α
⊢ (∃ t a, (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s + t ∧ s' = erase (s + t) a) ↔
    ∃ t a, (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ s' = erase s a + t
[PROOFSTEP]
refine' exists₂_congr fun t a ↦ ⟨_, _⟩
[GOAL]
case refine'_1
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s' s t : Multiset α
a : α
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s + t ∧ s' = erase (s + t) a →
    (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ s' = erase s a + t
[PROOFSTEP]
rintro ⟨ht, ha, rfl⟩
[GOAL]
case refine'_1.intro.intro
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t : Multiset α
a : α
ht : ∀ (a' : α), a' ∈ t → r a' a
ha : a ∈ s + t
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ erase (s + t) a = erase s a + t
[PROOFSTEP]
obtain h | h := mem_add.1 ha
[GOAL]
case refine'_1.intro.intro.inl
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t : Multiset α
a : α
ht : ∀ (a' : α), a' ∈ t → r a' a
ha : a ∈ s + t
h : a ∈ s
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ erase (s + t) a = erase s a + t
case refine'_1.intro.intro.inr
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t : Multiset α
a : α
ht : ∀ (a' : α), a' ∈ t → r a' a
ha : a ∈ s + t
h : a ∈ t
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ erase (s + t) a = erase s a + t
[PROOFSTEP]
exacts [⟨ht, h, erase_add_left_pos t h⟩, (@irrefl α r _ a (ht a h)).elim]
[GOAL]
case refine'_2
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s' s t : Multiset α
a : α
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s ∧ s' = erase s a + t →
    (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s + t ∧ s' = erase (s + t) a
[PROOFSTEP]
rintro ⟨ht, h, rfl⟩
[GOAL]
case refine'_2.intro.intro
α : Type u_1
r : α → α → Prop
inst✝¹ : DecidableEq α
inst✝ : IsIrrefl α r
s t : Multiset α
a : α
ht : ∀ (a' : α), a' ∈ t → r a' a
h : a ∈ s
⊢ (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ s + t ∧ erase s a + t = erase (s + t) a
[PROOFSTEP]
exact ⟨ht, mem_add.2 (Or.inl h), (erase_add_left_pos t h).symm⟩
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
s : Multiset α
⊢ ¬CutExpand r s 0
[PROOFSTEP]
classical
rw [cutExpand_iff]
rintro ⟨_, _, _, ⟨⟩, _⟩
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
s : Multiset α
⊢ ¬CutExpand r s 0
[PROOFSTEP]
rw [cutExpand_iff]
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
s : Multiset α
⊢ ¬∃ t a, (∀ (a' : α), a' ∈ t → r a' a) ∧ a ∈ 0 ∧ s = erase 0 a + t
[PROOFSTEP]
rintro ⟨_, _, _, ⟨⟩, _⟩
[GOAL]
α : Type u_1
r✝ r : α → α → Prop
⊢ Fibration (GameAdd (CutExpand r) (CutExpand r)) (CutExpand r) fun s => s.fst + s.snd
[PROOFSTEP]
rintro ⟨s₁, s₂⟩ s ⟨t, a, hr, he⟩
[GOAL]
case mk.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = (fun s => s.fst + s.snd) (s₁, s₂) + t
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ (fun s => s.fst + s.snd) a' = s
[PROOFSTEP]
dsimp at he ⊢
[GOAL]
case mk.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = s
[PROOFSTEP]
classical
  -- Porting note: Originally `obtain ⟨ha, rfl⟩`
    -- This is https://github.com/leanprover/std4/issues/62
obtain ⟨ha, hb⟩ := add_singleton_eq_iff.1 he
rw [hb]
rw [add_assoc, mem_add] at ha
obtain h | h := ha
· refine' ⟨(s₁.erase a + t, s₂), GameAdd.fst ⟨t, a, hr, _⟩, _⟩
  · rw [add_comm, ← add_assoc, singleton_add, cons_erase h]
  · rw [add_assoc s₁, erase_add_left_pos _ h, add_right_comm, add_assoc]
· refine' ⟨(s₁, (s₂ + t).erase a), GameAdd.snd ⟨t, a, hr, _⟩, _⟩
  · rw [add_comm, singleton_add, cons_erase h]
  · rw [add_assoc, erase_add_right_pos _ h]
[GOAL]
case mk.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = s
[PROOFSTEP]
obtain ⟨ha, hb⟩ := add_singleton_eq_iff.1 he
[GOAL]
case mk.intro.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
ha : a ∈ s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = s
[PROOFSTEP]
rw [hb]
[GOAL]
case mk.intro.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
ha : a ∈ s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
rw [add_assoc, mem_add] at ha
[GOAL]
case mk.intro.intro.intro.intro
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
ha : a ∈ s₁ ∨ a ∈ s₂ + t
hb : s = erase (s₁ + s₂ + t) a
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
obtain h | h := ha
[GOAL]
case mk.intro.intro.intro.intro.inl
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₁
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
refine' ⟨(s₁.erase a + t, s₂), GameAdd.fst ⟨t, a, hr, _⟩, _⟩
[GOAL]
case mk.intro.intro.intro.intro.inl.refine'_1
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₁
⊢ erase s₁ a + t + {a} = s₁ + t
[PROOFSTEP]
rw [add_comm, ← add_assoc, singleton_add, cons_erase h]
[GOAL]
case mk.intro.intro.intro.intro.inl.refine'_2
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₁
⊢ (erase s₁ a + t, s₂).fst + (erase s₁ a + t, s₂).snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
rw [add_assoc s₁, erase_add_left_pos _ h, add_right_comm, add_assoc]
[GOAL]
case mk.intro.intro.intro.intro.inr
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₂ + t
⊢ ∃ a', GameAdd (CutExpand r) (CutExpand r) a' (s₁, s₂) ∧ a'.fst + a'.snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
refine' ⟨(s₁, (s₂ + t).erase a), GameAdd.snd ⟨t, a, hr, _⟩, _⟩
[GOAL]
case mk.intro.intro.intro.intro.inr.refine'_1
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₂ + t
⊢ erase (s₂ + t) a + {a} = s₂ + t
[PROOFSTEP]
rw [add_comm, singleton_add, cons_erase h]
[GOAL]
case mk.intro.intro.intro.intro.inr.refine'_2
α : Type u_1
r✝ r : α → α → Prop
s₁ s₂ s t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
he : s + {a} = s₁ + s₂ + t
hb : s = erase (s₁ + s₂ + t) a
h : a ∈ s₂ + t
⊢ (s₁, erase (s₂ + t) a).fst + (s₁, erase (s₂ + t) a).snd = erase (s₁ + s₂ + t) a
[PROOFSTEP]
rw [add_assoc, erase_add_right_pos _ h]
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
s : Multiset α
hs : ∀ (a : α), a ∈ s → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) s
[PROOFSTEP]
induction s using Multiset.induction
[GOAL]
case empty
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
hs : ∀ (a : α), a ∈ 0 → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) 0
case cons
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝¹ : α
s✝ : Multiset α
a✝ : (∀ (a : α), a ∈ s✝ → Acc (CutExpand r) {a}) → Acc (CutExpand r) s✝
hs : ∀ (a : α), a ∈ a✝¹ ::ₘ s✝ → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) (a✝¹ ::ₘ s✝)
[PROOFSTEP]
case empty => exact Acc.intro 0 fun s h ↦ (not_cutExpand_zero s h).elim
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
hs : ∀ (a : α), a ∈ 0 → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) 0
[PROOFSTEP]
case empty => exact Acc.intro 0 fun s h ↦ (not_cutExpand_zero s h).elim
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
hs : ∀ (a : α), a ∈ 0 → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) 0
[PROOFSTEP]
exact Acc.intro 0 fun s h ↦ (not_cutExpand_zero s h).elim
[GOAL]
case cons
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝¹ : α
s✝ : Multiset α
a✝ : (∀ (a : α), a ∈ s✝ → Acc (CutExpand r) {a}) → Acc (CutExpand r) s✝
hs : ∀ (a : α), a ∈ a✝¹ ::ₘ s✝ → Acc (CutExpand r) {a}
⊢ Acc (CutExpand r) (a✝¹ ::ₘ s✝)
[PROOFSTEP]
case cons a s ihs =>
  rw [← s.singleton_add a]
  rw [forall_mem_cons] at hs
  exact (hs.1.prod_gameAdd <| ihs fun a ha ↦ hs.2 a ha).of_fibration _ (cutExpand_fibration r)
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a : α
s : Multiset α
ihs : (∀ (a : α), a ∈ s → Acc (CutExpand r) {a}) → Acc (CutExpand r) s
hs : ∀ (a_1 : α), a_1 ∈ a ::ₘ s → Acc (CutExpand r) {a_1}
⊢ Acc (CutExpand r) (a ::ₘ s)
[PROOFSTEP]
case cons a s ihs =>
  rw [← s.singleton_add a]
  rw [forall_mem_cons] at hs
  exact (hs.1.prod_gameAdd <| ihs fun a ha ↦ hs.2 a ha).of_fibration _ (cutExpand_fibration r)
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a : α
s : Multiset α
ihs : (∀ (a : α), a ∈ s → Acc (CutExpand r) {a}) → Acc (CutExpand r) s
hs : ∀ (a_1 : α), a_1 ∈ a ::ₘ s → Acc (CutExpand r) {a_1}
⊢ Acc (CutExpand r) (a ::ₘ s)
[PROOFSTEP]
rw [← s.singleton_add a]
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a : α
s : Multiset α
ihs : (∀ (a : α), a ∈ s → Acc (CutExpand r) {a}) → Acc (CutExpand r) s
hs : ∀ (a_1 : α), a_1 ∈ a ::ₘ s → Acc (CutExpand r) {a_1}
⊢ Acc (CutExpand r) ({a} + s)
[PROOFSTEP]
rw [forall_mem_cons] at hs
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a : α
s : Multiset α
ihs : (∀ (a : α), a ∈ s → Acc (CutExpand r) {a}) → Acc (CutExpand r) s
hs : Acc (CutExpand r) {a} ∧ ∀ (x : α), x ∈ s → Acc (CutExpand r) {x}
⊢ Acc (CutExpand r) ({a} + s)
[PROOFSTEP]
exact (hs.1.prod_gameAdd <| ihs fun a ha ↦ hs.2 a ha).of_fibration _ (cutExpand_fibration r)
[GOAL]
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a : α
hacc : Acc r a
⊢ Acc (CutExpand r) {a}
[PROOFSTEP]
induction' hacc with a h ih
[GOAL]
case intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ a : α
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
⊢ Acc (CutExpand r) {a}
[PROOFSTEP]
refine' Acc.intro _ fun s ↦ _
[GOAL]
case intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ a : α
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
s : Multiset α
⊢ CutExpand r s {a} → Acc (CutExpand r) s
[PROOFSTEP]
classical
simp only [cutExpand_iff, mem_singleton]
rintro ⟨t, a, hr, rfl, rfl⟩
refine' acc_of_singleton fun a' ↦ _
rw [erase_singleton, zero_add]
exact ih a' ∘ hr a'
[GOAL]
case intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ a : α
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
s : Multiset α
⊢ CutExpand r s {a} → Acc (CutExpand r) s
[PROOFSTEP]
simp only [cutExpand_iff, mem_singleton]
[GOAL]
case intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ a : α
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
s : Multiset α
⊢ (∃ t a_1, (∀ (a' : α), a' ∈ t → r a' a_1) ∧ a_1 = a ∧ s = erase {a} a_1 + t) → Acc (CutExpand r) s
[PROOFSTEP]
rintro ⟨t, a, hr, rfl, rfl⟩
[GOAL]
case intro.intro.intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ : α
t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
⊢ Acc (CutExpand r) (erase {a} a + t)
[PROOFSTEP]
refine' acc_of_singleton fun a' ↦ _
[GOAL]
case intro.intro.intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ : α
t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
a' : α
⊢ a' ∈ erase {a} a + t → Acc (CutExpand r) {a'}
[PROOFSTEP]
rw [erase_singleton, zero_add]
[GOAL]
case intro.intro.intro.intro.intro
α : Type u_1
r : α → α → Prop
inst✝ : IsIrrefl α r
a✝ : α
t : Multiset α
a : α
hr : ∀ (a' : α), a' ∈ t → r a' a
h : ∀ (y : α), r y a → Acc r y
ih : ∀ (y : α), r y a → Acc (CutExpand r) {y}
a' : α
⊢ a' ∈ t → Acc (CutExpand r) {a'}
[PROOFSTEP]
exact ih a' ∘ hr a'


[GOAL]
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ diagram F U ⋙ G ≅ diagram (F ⋙ G) U
[PROOFSTEP]
fapply NatIso.ofComponents
[GOAL]
case app
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (X_1 : WalkingParallelPair) → (diagram F U ⋙ G).obj X_1 ≅ (diagram (F ⋙ G) U).obj X_1
case naturality
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ autoParam
    (∀ {X_1 Y : WalkingParallelPair} (f : X_1 ⟶ Y),
      (diagram F U ⋙ G).map f ≫ (?app Y).hom = (?app X_1).hom ≫ (diagram (F ⋙ G) U).map f)
    _auto✝
[PROOFSTEP]
rintro ⟨j⟩
[GOAL]
case app.zero
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).obj WalkingParallelPair.zero ≅ (diagram (F ⋙ G) U).obj WalkingParallelPair.zero
case app.one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).obj WalkingParallelPair.one ≅ (diagram (F ⋙ G) U).obj WalkingParallelPair.one
case naturality
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ autoParam
    (∀ {X_1 Y : WalkingParallelPair} (f : X_1 ⟶ Y),
      (diagram F U ⋙ G).map f ≫ (?m.6024 Y).hom = (?m.6024 X_1).hom ≫ (diagram (F ⋙ G) U).map f)
    _auto✝
[PROOFSTEP]
exact PreservesProduct.iso _ _
[GOAL]
case app.one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).obj WalkingParallelPair.one ≅ (diagram (F ⋙ G) U).obj WalkingParallelPair.one
case naturality
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ autoParam
    (∀ {X_1 Y : WalkingParallelPair} (f : X_1 ⟶ Y),
      (diagram F U ⋙ G).map f ≫ (?m.6024 Y).hom = (?m.6024 X_1).hom ≫ (diagram (F ⋙ G) U).map f)
    _auto✝
[PROOFSTEP]
exact PreservesProduct.iso _ _
[GOAL]
case naturality
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ autoParam
    (∀ {X_1 Y : WalkingParallelPair} (f : X_1 ⟶ Y),
      (diagram F U ⋙ G).map f ≫
          (WalkingParallelPair.casesOn Y (PreservesProduct.iso G fun i => F.obj (op (U i)))
              (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom =
        (WalkingParallelPair.casesOn X_1 (PreservesProduct.iso G fun i => F.obj (op (U i)))
              (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
          (diagram (F ⋙ G) U).map f)
    _auto✝
[PROOFSTEP]
rintro ⟨⟩ ⟨⟩ ⟨⟩
[GOAL]
case naturality.zero.zero.id
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).map (WalkingParallelPairHom.id WalkingParallelPair.zero) ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
      (diagram (F ⋙ G) U).map (WalkingParallelPairHom.id WalkingParallelPair.zero)
[PROOFSTEP]
refine limit.hom_ext (fun j => ?_)
[GOAL]
case naturality.zero.zero.id
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete ι
⊢ ((diagram F U ⋙ G).map (WalkingParallelPairHom.id WalkingParallelPair.zero) ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom) ≫
      limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
        (diagram (F ⋙ G) U).map (WalkingParallelPairHom.id WalkingParallelPair.zero)) ≫
      limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j
[PROOFSTEP]
simp
[GOAL]
case naturality.zero.one.left
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).map WalkingParallelPairHom.left ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
      (diagram (F ⋙ G) U).map WalkingParallelPairHom.left
[PROOFSTEP]
refine
  limit.hom_ext
    (fun j => ?_)
      -- Porting note : `attribute [local reducible]` doesn't work, this is its replacement
[GOAL]
case naturality.zero.one.left
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ ((diagram F U ⋙ G).map WalkingParallelPairHom.left ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
        (diagram (F ⋙ G) U).map WalkingParallelPairHom.left) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j
[PROOFSTEP]
dsimp [diagram, leftRes, rightRes]
[GOAL]
case naturality.zero.one.left
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ (G.map (Pi.lift fun p => Pi.π (fun i => F.obj (op (U i))) p.fst ≫ F.map (Opens.infLELeft (U p.fst) (U p.snd)).op) ≫
        piComparison G fun p => F.obj (op (U p.fst ⊓ U p.snd))) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j =
    ((piComparison G fun i => F.obj (op (U i))) ≫
        Pi.lift fun p =>
          Pi.π (fun i => G.obj (F.obj (op (U i)))) p.fst ≫ G.map (F.map (Opens.infLELeft (U p.fst) (U p.snd)).op)) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j
[PROOFSTEP]
simp [limit.lift_π, Functor.comp_map, map_lift_piComparison, Fan.mk_π_app, PreservesProduct.iso_hom,
  parallelPair_map_left, Functor.map_comp, Category.assoc]
[GOAL]
case naturality.zero.one.right
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).map WalkingParallelPairHom.right ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
      (diagram (F ⋙ G) U).map WalkingParallelPairHom.right
[PROOFSTEP]
refine
  limit.hom_ext
    (fun j => ?_)
      -- Porting note : `attribute [local reducible]` doesn't work, this is its replacement
[GOAL]
case naturality.zero.one.right
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ ((diagram F U ⋙ G).map WalkingParallelPairHom.right ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
        (diagram (F ⋙ G) U).map WalkingParallelPairHom.right) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j
[PROOFSTEP]
dsimp [diagram, leftRes, rightRes]
[GOAL]
case naturality.zero.one.right
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ (G.map (Pi.lift fun p => Pi.π (fun i => F.obj (op (U i))) p.snd ≫ F.map (Opens.infLERight (U p.fst) (U p.snd)).op) ≫
        piComparison G fun p => F.obj (op (U p.fst ⊓ U p.snd))) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j =
    ((piComparison G fun i => F.obj (op (U i))) ≫
        Pi.lift fun p =>
          Pi.π (fun i => G.obj (F.obj (op (U i)))) p.snd ≫ G.map (F.map (Opens.infLERight (U p.fst) (U p.snd)).op)) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j
[PROOFSTEP]
simp [limit.lift_π, Functor.comp_map, map_lift_piComparison, Fan.mk_π_app, PreservesProduct.iso_hom,
  parallelPair_map_left, Functor.map_comp, Category.assoc]
[GOAL]
case naturality.one.one.id
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ (diagram F U ⋙ G).map (WalkingParallelPairHom.id WalkingParallelPair.one) ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
      (diagram (F ⋙ G) U).map (WalkingParallelPairHom.id WalkingParallelPair.one)
[PROOFSTEP]
refine limit.hom_ext (fun j => ?_)
[GOAL]
case naturality.one.one.id
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ ((diagram F U ⋙ G).map (WalkingParallelPairHom.id WalkingParallelPair.one) ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso G fun i => F.obj (op (U i)))
            (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd)))).hom ≫
        (diagram (F ⋙ G) U).map (WalkingParallelPairHom.id WalkingParallelPair.one)) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j
[PROOFSTEP]
simp [diagram, leftRes, rightRes]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : WalkingParallelPair
⊢ NatTrans.app (G.mapCone (fork F U)).π j =
    (Iso.refl (G.mapCone (fork F U)).pt).hom ≫
      NatTrans.app ((Cones.postcompose (diagramCompPreservesLimits G F U).inv).obj (fork (F ⋙ G) U)).π j
[PROOFSTEP]
dsimp
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : WalkingParallelPair
⊢ G.map (NatTrans.app (fork F U).π j) =
    𝟙 (G.obj (F.obj (op (iSup U)))) ≫
      NatTrans.app (fork (F ⋙ G) U).π j ≫ NatTrans.app (diagramCompPreservesLimits G F U).inv j
[PROOFSTEP]
simp [diagramCompPreservesLimits]
[GOAL]
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : WalkingParallelPair
⊢ G.map (NatTrans.app (fork F U).π j) =
    NatTrans.app (fork (F ⋙ G) U).π j ≫
      (WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) j).inv
[PROOFSTEP]
cases j
[GOAL]
case zero
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (NatTrans.app (fork F U).π WalkingParallelPair.zero) =
    NatTrans.app (fork (F ⋙ G) U).π WalkingParallelPair.zero ≫
      (WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) WalkingParallelPair.zero).inv
[PROOFSTEP]
dsimp
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (NatTrans.app (fork F U).π WalkingParallelPair.one) =
    NatTrans.app (fork (F ⋙ G) U).π WalkingParallelPair.one ≫
      (WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
          (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) WalkingParallelPair.one).inv
[PROOFSTEP]
dsimp
[GOAL]
case zero
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (res F U) = res (F ⋙ G) U ≫ (PreservesProduct.iso G fun i => F.obj (op (U i))).inv
[PROOFSTEP]
rw [Iso.eq_comp_inv]
  -- Porting note : `ext` can't see `limit.hom_ext` applies here:
        -- See https://github.com/leanprover-community/mathlib4/issues/5229
[GOAL]
case zero
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (res F U) ≫ (PreservesProduct.iso G fun i => F.obj (op (U i))).hom = res (F ⋙ G) U
[PROOFSTEP]
refine
  limit.hom_ext
    (fun j => ?_)
      -- Porting note : `attribute [local reducible]` doesn't work, this is its replacement
[GOAL]
case zero
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete ι
⊢ (G.map (res F U) ≫ (PreservesProduct.iso G fun i => F.obj (op (U i))).hom) ≫
      limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j =
    res (F ⋙ G) U ≫ limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j
[PROOFSTEP]
simp [diagram, leftRes, rightRes, res]
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (res F U ≫ leftRes F U) =
    (res (F ⋙ G) U ≫ leftRes (F ⋙ G) U) ≫ (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))).inv
[PROOFSTEP]
rw [Iso.eq_comp_inv]
  -- Porting note : `ext` can't see `limit.hom_ext` applies here:
        -- See https://github.com/leanprover-community/mathlib4/issues/5229
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
⊢ G.map (res F U ≫ leftRes F U) ≫ (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))).hom =
    res (F ⋙ G) U ≫ leftRes (F ⋙ G) U
[PROOFSTEP]
refine
  limit.hom_ext
    (fun j => ?_)
      -- Porting note : `attribute [local reducible]` doesn't work, this is its replacement
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ (G.map (res F U ≫ leftRes F U) ≫ (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))).hom) ≫
      limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j =
    (res (F ⋙ G) U ≫ leftRes (F ⋙ G) U) ≫ limit.π (Discrete.functor fun p => (F ⋙ G).obj (op (U p.fst ⊓ U p.snd))) j
[PROOFSTEP]
dsimp [diagram, leftRes, rightRes, res]
  -- Porting note : there used to be a non-terminal `simp` for `squeeze_simp` did not work,
        -- however, `simp?` works fine now, but in both mathlib3 and mathlib4, two `simp`s are
        -- required to close goal
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ (G.map
          ((Pi.lift fun i => F.map (Opens.leSupr U i).op) ≫
            Pi.lift fun p => Pi.π (fun i => F.obj (op (U i))) p.fst ≫ F.map (Opens.infLELeft (U p.fst) (U p.snd)).op) ≫
        piComparison G fun p => F.obj (op (U p.fst ⊓ U p.snd))) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j =
    ((Pi.lift fun i => G.map (F.map (Opens.leSupr U i).op)) ≫
        Pi.lift fun p =>
          Pi.π (fun i => G.obj (F.obj (op (U i)))) p.fst ≫ G.map (F.map (Opens.infLELeft (U p.fst) (U p.snd)).op)) ≫
      limit.π (Discrete.functor fun p => G.obj (F.obj (op (U p.fst ⊓ U p.snd)))) j
[PROOFSTEP]
simp only [Functor.map_comp, Category.assoc, map_lift_piComparison, limit.lift_π, Fan.mk_pt, Fan.mk_π_app,
  limit.lift_π_assoc, Discrete.functor_obj]
[GOAL]
case one
C : Type u₁
inst✝⁴ : Category.{v, u₁} C
inst✝³ : HasLimits C
D : Type u₂
inst✝² : Category.{v, u₂} D
inst✝¹ : HasLimits D
G : C ⥤ D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
ι : Type v
U : ι → Opens ↑X
j : Discrete (ι × ι)
⊢ G.map (Pi.lift fun i => F.map (Opens.leSupr U i).op) ≫
      G.map (Pi.π (fun i => F.obj (op (U i))) j.as.fst) ≫ G.map (F.map (Opens.infLELeft (U j.as.fst) (U j.as.snd)).op) =
    G.map (F.map (Opens.leSupr U j.as.fst).op) ≫ G.map (F.map (Opens.infLELeft (U j.as.fst) (U j.as.snd)).op)
[PROOFSTEP]
simp only [limit.lift_π, Fan.mk_π_app, ← G.map_comp, limit.lift_π_assoc, Fan.mk_π_app]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
⊢ IsSheaf F ↔ IsSheaf (F ⋙ G)
[PROOFSTEP]
rw [Presheaf.isSheaf_iff_isSheafEqualizerProducts, Presheaf.isSheaf_iff_isSheafEqualizerProducts]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
⊢ IsSheafEqualizerProducts F ↔ IsSheafEqualizerProducts (F ⋙ G)
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
⊢ IsSheafEqualizerProducts F → IsSheafEqualizerProducts (F ⋙ G)
[PROOFSTEP]
intro S ι U
[GOAL]
case mp
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
obtain ⟨t₁⟩ := S U
[GOAL]
case mp.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
t₁ : IsLimit (fork F U)
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
letI := preservesSmallestLimitsOfPreservesLimits G
[GOAL]
case mp.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
t₁ : IsLimit (fork F U)
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
have t₂ := @PreservesLimit.preserves _ _ _ _ _ _ _ G _ _ t₁
[GOAL]
case mp.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
t₁ : IsLimit (fork F U)
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
t₂ : IsLimit (G.mapCone (fork F U))
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
have t₃ :=
  IsLimit.ofIsoLimit t₂
    (mapConeFork G F U)
      -- and as postcomposing by a natural isomorphism preserves limit cones,
[GOAL]
case mp.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
t₁ : IsLimit (fork F U)
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
t₂ : IsLimit (G.mapCone (fork F U))
t₃ : IsLimit ((Cones.postcompose (diagramCompPreservesLimits G F U).inv).obj (fork (F ⋙ G) U))
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
have t₄ := IsLimit.postcomposeInvEquiv _ _ t₃
[GOAL]
case mp.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts F
ι : Type v
U : ι → Opens ↑X
t₁ : IsLimit (fork F U)
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
t₂ : IsLimit (G.mapCone (fork F U))
t₃ : IsLimit ((Cones.postcompose (diagramCompPreservesLimits G F U).inv).obj (fork (F ⋙ G) U))
t₄ : (fun x => IsLimit (fork (F ⋙ G) U)) t₃
⊢ Nonempty (IsLimit (fork (F ⋙ G) U))
[PROOFSTEP]
exact ⟨t₄⟩
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
⊢ IsSheafEqualizerProducts (F ⋙ G) → IsSheafEqualizerProducts F
[PROOFSTEP]
intro S ι U
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
⊢ Nonempty (IsLimit (fork F U))
[PROOFSTEP]
refine'
  ⟨_⟩
    -- Let `f` be the universal morphism from `F.obj U` to the equalizer
        -- of the sheaf condition fork, whatever it is.
        -- Our goal is to show that this is an isomorphism.
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
⊢ IsLimit (fork F U)
[PROOFSTEP]
let f :=
  equalizer.lift _
    (w F U)
      -- If we can do that,
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
⊢ IsLimit (fork F U)
[PROOFSTEP]
suffices IsIso (G.map f)
  by
  skip
    -- we have that `f` itself is an isomorphism, since `G` reflects isomorphisms
  haveI : IsIso f := isIso_of_reflects_iso f G
  apply IsLimit.ofIsoLimit (limit.isLimit _)
  apply Iso.symm
  fapply Cones.ext
  exact asIso f
  rintro ⟨_ | _⟩ <;> · simp
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this : IsIso (G.map f)
⊢ IsLimit (fork F U)
[PROOFSTEP]
skip
  -- we have that `f` itself is an isomorphism, since `G` reflects isomorphisms
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this : IsIso (G.map f)
⊢ IsLimit (fork F U)
[PROOFSTEP]
haveI : IsIso f := isIso_of_reflects_iso f G
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ IsLimit (fork F U)
[PROOFSTEP]
apply IsLimit.ofIsoLimit (limit.isLimit _)
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ limit.cone (parallelPair (leftRes F U) (rightRes F U)) ≅ fork F U
[PROOFSTEP]
apply Iso.symm
[GOAL]
case I
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ fork F U ≅ limit.cone (parallelPair (leftRes F U) (rightRes F U))
[PROOFSTEP]
fapply Cones.ext
[GOAL]
case I.φ
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ (fork F U).pt ≅ (limit.cone (parallelPair (leftRes F U) (rightRes F U))).pt
case I.w
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ autoParam
    (∀ (j : WalkingParallelPair),
      NatTrans.app (fork F U).π j =
        ?I.φ.hom ≫ NatTrans.app (limit.cone (parallelPair (leftRes F U) (rightRes F U))).π j)
    _auto✝
[PROOFSTEP]
exact asIso f
[GOAL]
case I.w
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ autoParam
    (∀ (j : WalkingParallelPair),
      NatTrans.app (fork F U).π j =
        (asIso f).hom ≫ NatTrans.app (limit.cone (parallelPair (leftRes F U) (rightRes F U))).π j)
    _auto✝
[PROOFSTEP]
rintro ⟨_ | _⟩
[GOAL]
case I.w.zero
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ NatTrans.app (fork F U).π WalkingParallelPair.zero =
    (asIso f).hom ≫ NatTrans.app (limit.cone (parallelPair (leftRes F U) (rightRes F U))).π WalkingParallelPair.zero
[PROOFSTEP]
simp
[GOAL]
case I.w.one
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
this✝ : IsIso (G.map f)
this : IsIso f
⊢ NatTrans.app (fork F U).π WalkingParallelPair.one =
    (asIso f).hom ≫ NatTrans.app (limit.cone (parallelPair (leftRes F U) (rightRes F U))).π WalkingParallelPair.one
[PROOFSTEP]
simp
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
⊢ IsIso (G.map f)
[PROOFSTEP]
let c := fork (F ⋙ G) U
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
⊢ IsIso (G.map f)
[PROOFSTEP]
obtain ⟨hc⟩ := S U
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
⊢ IsIso (G.map f)
[PROOFSTEP]
let d := G.mapCone (equalizer.fork (leftRes.{v} F U) (rightRes F U))
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
⊢ IsIso (G.map f)
[PROOFSTEP]
letI := preservesSmallestLimitsOfPreservesLimits G
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
⊢ IsIso (G.map f)
[PROOFSTEP]
have hd : IsLimit d :=
  PreservesLimit.preserves
    (limit.isLimit _)
      -- Since both of these are limit cones
            -- (`c` by our hypothesis `S`, and `d` because `G` preserves limits),
            -- we hope to be able to conclude that `f` is an isomorphism.
            -- We say "not quite" above because `c` and `d` don't quite have the same shape:
            -- we need to postcompose by the natural isomorphism `diagramCompPreservesLimits`
            -- introduced above.
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
⊢ IsIso (G.map f)
[PROOFSTEP]
let d' := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
⊢ IsIso (G.map f)
[PROOFSTEP]
have hd' : IsLimit d' := (IsLimit.postcomposeHomEquiv (diagramCompPreservesLimits G F U : _) d).symm hd
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
⊢ IsIso (G.map f)
[PROOFSTEP]
let f' : c ⟶ d' :=
  Fork.mkHom (G.map f)
    (by
      dsimp only [diagramCompPreservesLimits, res]
      dsimp only [Fork.ι]
        -- Porting note : `ext` can't see `limit.hom_ext` applies here:
                -- See https://github.com/leanprover-community/mathlib4/issues/5229
      refine limit.hom_ext fun j => ?_
      dsimp
      simp only [Category.assoc, ← Functor.map_comp_assoc, equalizer.lift_ι, map_lift_piComparison_assoc]
      dsimp [res])
      -- conclude that it is an isomorphism,
            -- just because it's a morphism between two limit cones.
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
⊢ G.map f ≫ Fork.ι d' = Fork.ι c
[PROOFSTEP]
dsimp only [diagramCompPreservesLimits, res]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
⊢ G.map
        (equalizer.lift (Pi.lift fun i => F.map (Opens.leSupr U i).op)
          (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)) ≫
      Fork.ι
        ((Cones.postcompose
              (NatIso.ofComponents fun X_1 =>
                  WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
                    (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) X_1).hom).obj
          (G.mapCone (equalizer.fork (leftRes F U) (rightRes F U)))) =
    Fork.ι (fork (F ⋙ G) U)
[PROOFSTEP]
dsimp only [Fork.ι]
  -- Porting note : `ext` can't see `limit.hom_ext` applies here:
          -- See https://github.com/leanprover-community/mathlib4/issues/5229
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
⊢ G.map
        (equalizer.lift (Pi.lift fun i => F.map (Opens.leSupr U i).op)
          (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)) ≫
      NatTrans.app
        ((Cones.postcompose
                (NatIso.ofComponents fun X_1 =>
                    WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
                      (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) X_1).hom).obj
            (G.mapCone (equalizer.fork (leftRes F U) (rightRes F U)))).π
        WalkingParallelPair.zero =
    NatTrans.app (fork (F ⋙ G) U).π WalkingParallelPair.zero
[PROOFSTEP]
refine limit.hom_ext fun j => ?_
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
j : Discrete ι
⊢ (G.map
          (equalizer.lift (Pi.lift fun i => F.map (Opens.leSupr U i).op)
            (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)) ≫
        NatTrans.app
          ((Cones.postcompose
                  (NatIso.ofComponents fun X_1 =>
                      WalkingParallelPair.rec (PreservesProduct.iso G fun i => F.obj (op (U i)))
                        (PreservesProduct.iso G fun p => F.obj (op (U p.fst ⊓ U p.snd))) X_1).hom).obj
              (G.mapCone (equalizer.fork (leftRes F U) (rightRes F U)))).π
          WalkingParallelPair.zero) ≫
      limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j =
    NatTrans.app (fork (F ⋙ G) U).π WalkingParallelPair.zero ≫
      limit.π (Discrete.functor fun i => (F ⋙ G).obj (op (U i))) j
[PROOFSTEP]
dsimp
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
j : Discrete ι
⊢ (G.map
          (equalizer.lift (Pi.lift fun i => F.map (Opens.leSupr U i).op)
            (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)) ≫
        G.map (equalizer.ι (leftRes F U) (rightRes F U)) ≫ piComparison G fun i => F.obj (op (U i))) ≫
      limit.π (Discrete.functor fun i => G.obj (F.obj (op (U i)))) j =
    res (F ⋙ G) U ≫ limit.π (Discrete.functor fun i => G.obj (F.obj (op (U i)))) j
[PROOFSTEP]
simp only [Category.assoc, ← Functor.map_comp_assoc, equalizer.lift_ι, map_lift_piComparison_assoc]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
j : Discrete ι
⊢ (Pi.lift fun j => G.map (F.map (Opens.leSupr U j).op)) ≫
      limit.π (Discrete.functor fun i => G.obj (F.obj (op (U i)))) j =
    res (F ⋙ G) U ≫ limit.π (Discrete.functor fun i => G.obj (F.obj (op (U i)))) j
[PROOFSTEP]
dsimp [res]
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
f' : c ⟶ d' := Fork.mkHom (G.map f) (_ : G.map f ≫ Fork.ι d' = Fork.ι c)
⊢ IsIso (G.map f)
[PROOFSTEP]
haveI : IsIso f' := IsLimit.hom_isIso hc hd' f'
[GOAL]
case mpr.intro
C : Type u₁
inst✝⁵ : Category.{v, u₁} C
D : Type u₂
inst✝⁴ : Category.{v, u₂} D
G : C ⥤ D
inst✝³ : ReflectsIsomorphisms G
inst✝² : HasLimits C
inst✝¹ : HasLimits D
inst✝ : PreservesLimits G
X : TopCat
F : Presheaf C X
S : IsSheafEqualizerProducts (F ⋙ G)
ι : Type v
U : ι → Opens ↑X
f : F.obj (op (iSup U)) ⟶ equalizer (leftRes F U) (rightRes F U) :=
  equalizer.lift (res F U) (_ : res F U ≫ leftRes F U = res F U ≫ rightRes F U)
c : Fork (leftRes (F ⋙ G) U) (rightRes (F ⋙ G) U) := fork (F ⋙ G) U
hc : IsLimit (fork (F ⋙ G) U)
d : Cone (parallelPair (leftRes F U) (rightRes F U) ⋙ G) := G.mapCone (equalizer.fork (leftRes F U) (rightRes F U))
this✝ : PreservesLimitsOfSize.{0, 0, v, v, u₁, u₂} G := preservesSmallestLimitsOfPreservesLimits G
hd : IsLimit d
d' : Cone (diagram (F ⋙ G) U) := (Cones.postcompose (diagramCompPreservesLimits G F U).hom).obj d
hd' : IsLimit d'
f' : c ⟶ d' := Fork.mkHom (G.map f) (_ : G.map f ≫ Fork.ι d' = Fork.ι c)
this : IsIso f'
⊢ IsIso (G.map f)
[PROOFSTEP]
exact IsIso.of_iso ((Cones.forget _).mapIso (asIso f'))


[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F G H I : C ⥤ D
α β : F ⟶ G
h : α = β
X : C
⊢ app α X = app β X
[PROOFSTEP]
rw [h]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
E : Type u₃
inst✝¹ : Category.{v₃, u₃} E
F G H I : C ⥤ D
α : F ⟶ G
inst✝ : ∀ (X : C), Mono (app α X)
Z✝ : C ⥤ D
g h : Z✝ ⟶ F
eq : g ≫ α = h ≫ α
⊢ g = h
[PROOFSTEP]
ext X
[GOAL]
case w.h
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
E : Type u₃
inst✝¹ : Category.{v₃, u₃} E
F G H I : C ⥤ D
α : F ⟶ G
inst✝ : ∀ (X : C), Mono (app α X)
Z✝ : C ⥤ D
g h : Z✝ ⟶ F
eq : g ≫ α = h ≫ α
X : C
⊢ app g X = app h X
[PROOFSTEP]
rw [← cancel_mono (α.app X), ← comp_app, eq, comp_app]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
E : Type u₃
inst✝¹ : Category.{v₃, u₃} E
F G H I : C ⥤ D
α : F ⟶ G
inst✝ : ∀ (X : C), Epi (app α X)
Z✝ : C ⥤ D
g h : G ⟶ Z✝
eq : α ≫ g = α ≫ h
⊢ g = h
[PROOFSTEP]
ext X
[GOAL]
case w.h
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
E : Type u₃
inst✝¹ : Category.{v₃, u₃} E
F G H I : C ⥤ D
α : F ⟶ G
inst✝ : ∀ (X : C), Epi (app α X)
Z✝ : C ⥤ D
g h : G ⟶ Z✝
eq : α ≫ g = α ≫ h
X : C
⊢ app g X = app h X
[PROOFSTEP]
rw [← cancel_epi (α.app X), ← comp_app, eq, comp_app]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F G H✝ I✝ : C ⥤ D
H I : D ⥤ E
α : F ⟶ G
β : H ⟶ I
X Y : C
f : X ⟶ Y
⊢ (F ⋙ H).map f ≫ (fun X => app β (F.obj X) ≫ I.map (app α X)) Y =
    (fun X => app β (F.obj X) ≫ I.map (app α X)) X ≫ (G ⋙ I).map f
[PROOFSTEP]
rw [Functor.comp_map, Functor.comp_map, ← assoc, naturality, assoc, ← map_comp I, naturality, map_comp, assoc]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F G H✝ I : C ⥤ D
H : D ⥤ E
α : F ⟶ G
X : C
⊢ app (α ◫ 𝟙 H) X = H.map (app α X)
[PROOFSTEP]
simp
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F G H✝ I : C ⥤ D
H : E ⥤ C
α : F ⟶ G
X : E
⊢ app (𝟙 H ◫ α) X = app α (H.obj X)
[PROOFSTEP]
simp
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F G H I✝ : C ⥤ D
I J K : D ⥤ E
α : F ⟶ G
β : G ⟶ H
γ : I ⟶ J
δ : J ⟶ K
⊢ (α ≫ β) ◫ (γ ≫ δ) = (α ◫ γ) ≫ β ◫ δ
[PROOFSTEP]
aesop_cat
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F✝ G H I : C ⥤ D
F : C ⥤ D ⥤ E
X Y : C
e : X ≅ Y
Z : D
⊢ app (F.map e.hom) Z ≫ app (F.map e.inv) Z = 𝟙 ((F.obj X).obj Z)
[PROOFSTEP]
simp [← NatTrans.comp_app, ← Functor.map_comp]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
F✝ G H I : C ⥤ D
F : C ⥤ D ⥤ E
X Y : C
e : X ≅ Y
Z : D
⊢ app (F.map e.inv) Z ≫ app (F.map e.hom) Z = 𝟙 ((F.obj Y).obj Z)
[PROOFSTEP]
simp [← NatTrans.comp_app, ← Functor.map_comp]


[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j : J
⊢ coconeFun F j 0 = 0
[PROOFSTEP]
apply Quot.sound
[GOAL]
case a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j : J
⊢ Setoid.r (Prequotient.of j 0) zero
[PROOFSTEP]
apply Relation.zero
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j : J
⊢ ∀ (x y : ↑(F.obj j)),
    ZeroHom.toFun
        { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) }
        (x + y) =
      ZeroHom.toFun
          { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) }
          x +
        ZeroHom.toFun
          { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) } y
[PROOFSTEP]
intros
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j : J
x✝ y✝ : ↑(F.obj j)
⊢ ZeroHom.toFun
      { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) }
      (x✝ + y✝) =
    ZeroHom.toFun
        { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) }
        x✝ +
      ZeroHom.toFun
        { toFun := coconeFun F j, map_zero' := (_ : Quot.mk Setoid.r (Prequotient.of j 0) = Quot.mk Setoid.r zero) } y✝
[PROOFSTEP]
apply Quot.sound
[GOAL]
case a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j : J
x✝ y✝ : ↑(F.obj j)
⊢ Setoid.r (Prequotient.of j (x✝ + y✝)) (add (Prequotient.of j x✝) (Prequotient.of j y✝))
[PROOFSTEP]
apply Relation.add
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ coconeMorphism F j' = coconeMorphism F j
[PROOFSTEP]
ext
[GOAL]
case w
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j j' : J
f : j ⟶ j'
x✝ : ↑(F.obj j)
⊢ ↑(F.map f ≫ coconeMorphism F j') x✝ = ↑(coconeMorphism F j) x✝
[PROOFSTEP]
apply Quot.sound
[GOAL]
case w.a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j j' : J
f : j ⟶ j'
x✝ : ↑(F.obj j)
⊢ Setoid.r (Prequotient.of j' (↑(F.map f) x✝)) (Prequotient.of j x✝)
[PROOFSTEP]
apply Relation.map
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j j' : J
f : j ⟶ j'
x : ↑(F.obj j)
⊢ ↑(coconeMorphism F j') (↑(F.map f) x) = ↑(coconeMorphism F j) x
[PROOFSTEP]
rw [← cocone_naturality F f]
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
j j' : J
f : j ⟶ j'
x : ↑(F.obj j)
⊢ ↑(coconeMorphism F j') (↑(F.map f) x) = ↑(F.map f ≫ coconeMorphism F j') x
[PROOFSTEP]
rfl
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
⊢ ColimitType F → ↑s.pt
[PROOFSTEP]
fapply Quot.lift
[GOAL]
case f
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
⊢ Prequotient F → ↑s.pt
[PROOFSTEP]
exact descFunLift F s
[GOAL]
case a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
⊢ ∀ (a b : Prequotient F), Setoid.r a b → descFunLift F s a = descFunLift F s b
[PROOFSTEP]
intro x y r
[GOAL]
case a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
r : Setoid.r x y
⊢ descFunLift F s x = descFunLift F s y
[PROOFSTEP]
induction r with
| refl => rfl
| symm _ _ _ r_ih => exact r_ih.symm
| trans _ _ _ _ _ r_ih_h r_ih_k => exact Eq.trans r_ih_h r_ih_k
| map j j' f x => simpa only [descFunLift, Functor.const_obj_obj] using FunLike.congr_fun (s.ι.naturality f) x
| zero => simp
| neg => simp
| add => simp
| neg_1 _ _ _ r_ih => dsimp; rw [r_ih]
| add_1 _ _ _ _ r_ih => dsimp; rw [r_ih]
| add_2 _ _ _ _ r_ih => dsimp; rw [r_ih]
| zero_add => dsimp; rw [zero_add]
| add_zero => dsimp; rw [add_zero]
| add_left_neg => dsimp; rw [add_left_neg]
| add_comm => dsimp; rw [add_comm]
| add_assoc => dsimp; rw [add_assoc]
[GOAL]
case a
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
r : Setoid.r x y
⊢ descFunLift F s x = descFunLift F s y
[PROOFSTEP]
induction r with
| refl => rfl
| symm _ _ _ r_ih => exact r_ih.symm
| trans _ _ _ _ _ r_ih_h r_ih_k => exact Eq.trans r_ih_h r_ih_k
| map j j' f x => simpa only [descFunLift, Functor.const_obj_obj] using FunLike.congr_fun (s.ι.naturality f) x
| zero => simp
| neg => simp
| add => simp
| neg_1 _ _ _ r_ih => dsimp; rw [r_ih]
| add_1 _ _ _ _ r_ih => dsimp; rw [r_ih]
| add_2 _ _ _ _ r_ih => dsimp; rw [r_ih]
| zero_add => dsimp; rw [zero_add]
| add_zero => dsimp; rw [add_zero]
| add_left_neg => dsimp; rw [add_left_neg]
| add_comm => dsimp; rw [add_comm]
| add_assoc => dsimp; rw [add_assoc]
[GOAL]
case a.refl
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s x✝ = descFunLift F s x✝
[PROOFSTEP]

| refl => rfl
[GOAL]
case a.refl
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s x✝ = descFunLift F s x✝
[PROOFSTEP]
rfl
[GOAL]
case a.symm
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ y✝ : Prequotient F
x✝ : Relation F x✝¹ y✝
r_ih : descFunLift F s x✝¹ = descFunLift F s y✝
⊢ descFunLift F s y✝ = descFunLift F s x✝¹
[PROOFSTEP]

| symm _ _ _ r_ih => exact r_ih.symm
[GOAL]
case a.symm
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ y✝ : Prequotient F
x✝ : Relation F x✝¹ y✝
r_ih : descFunLift F s x✝¹ = descFunLift F s y✝
⊢ descFunLift F s y✝ = descFunLift F s x✝¹
[PROOFSTEP]
exact r_ih.symm
[GOAL]
case a.trans
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝² y✝ z✝ : Prequotient F
x✝¹ : Relation F x✝² y✝
x✝ : Relation F y✝ z✝
r_ih_h : descFunLift F s x✝² = descFunLift F s y✝
r_ih_k : descFunLift F s y✝ = descFunLift F s z✝
⊢ descFunLift F s x✝² = descFunLift F s z✝
[PROOFSTEP]

| trans _ _ _ _ _ r_ih_h r_ih_k => exact Eq.trans r_ih_h r_ih_k
[GOAL]
case a.trans
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝² y✝ z✝ : Prequotient F
x✝¹ : Relation F x✝² y✝
x✝ : Relation F y✝ z✝
r_ih_h : descFunLift F s x✝² = descFunLift F s y✝
r_ih_k : descFunLift F s y✝ = descFunLift F s z✝
⊢ descFunLift F s x✝² = descFunLift F s z✝
[PROOFSTEP]
exact Eq.trans r_ih_h r_ih_k
[GOAL]
case a.map
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x✝ y : Prequotient F
j j' : J
f : j ⟶ j'
x : ↑(F.obj j)
⊢ descFunLift F s (Prequotient.of j' (↑(F.map f) x)) = descFunLift F s (Prequotient.of j x)
[PROOFSTEP]

| map j j' f x => simpa only [descFunLift, Functor.const_obj_obj] using FunLike.congr_fun (s.ι.naturality f) x
[GOAL]
case a.map
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x✝ y : Prequotient F
j j' : J
f : j ⟶ j'
x : ↑(F.obj j)
⊢ descFunLift F s (Prequotient.of j' (↑(F.map f) x)) = descFunLift F s (Prequotient.of j x)
[PROOFSTEP]
simpa only [descFunLift, Functor.const_obj_obj] using FunLike.congr_fun (s.ι.naturality f) x
[GOAL]
case a.zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
⊢ descFunLift F s (Prequotient.of j✝ 0) = descFunLift F s zero
[PROOFSTEP]

| zero => simp
[GOAL]
case a.zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
⊢ descFunLift F s (Prequotient.of j✝ 0) = descFunLift F s zero
[PROOFSTEP]
simp
[GOAL]
case a.neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
x✝ : ↑(F.obj j✝)
⊢ descFunLift F s (Prequotient.of j✝ (-x✝)) = descFunLift F s (neg (Prequotient.of j✝ x✝))
[PROOFSTEP]

| neg => simp
[GOAL]
case a.neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
x✝ : ↑(F.obj j✝)
⊢ descFunLift F s (Prequotient.of j✝ (-x✝)) = descFunLift F s (neg (Prequotient.of j✝ x✝))
[PROOFSTEP]
simp
[GOAL]
case a.add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
x✝ y✝ : ↑(F.obj j✝)
⊢ descFunLift F s (Prequotient.of j✝ (x✝ + y✝)) = descFunLift F s (add (Prequotient.of j✝ x✝) (Prequotient.of j✝ y✝))
[PROOFSTEP]

| add => simp
[GOAL]
case a.add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : Prequotient F
j✝ : J
x✝ y✝ : ↑(F.obj j✝)
⊢ descFunLift F s (Prequotient.of j✝ (x✝ + y✝)) = descFunLift F s (add (Prequotient.of j✝ x✝) (Prequotient.of j✝ y✝))
[PROOFSTEP]
simp
[GOAL]
case a.neg_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ descFunLift F s (neg x✝¹) = descFunLift F s (neg x'✝)
[PROOFSTEP]

| neg_1 _ _ _ r_ih => dsimp; rw [r_ih]
[GOAL]
case a.neg_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ descFunLift F s (neg x✝¹) = descFunLift F s (neg x'✝)
[PROOFSTEP]
dsimp
[GOAL]
case a.neg_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ -descFunLift F s x✝¹ = -descFunLift F s x'✝
[PROOFSTEP]
rw [r_ih]
[GOAL]
case a.add_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ y✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ descFunLift F s (add x✝¹ y✝) = descFunLift F s (add x'✝ y✝)
[PROOFSTEP]

| add_1 _ _ _ _ r_ih => dsimp; rw [r_ih]
[GOAL]
case a.add_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ y✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ descFunLift F s (add x✝¹ y✝) = descFunLift F s (add x'✝ y✝)
[PROOFSTEP]
dsimp
[GOAL]
case a.add_1
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ x'✝ y✝ : Prequotient F
x✝ : Relation F x✝¹ x'✝
r_ih : descFunLift F s x✝¹ = descFunLift F s x'✝
⊢ descFunLift F s x✝¹ + descFunLift F s y✝ = descFunLift F s x'✝ + descFunLift F s y✝
[PROOFSTEP]
rw [r_ih]
[GOAL]
case a.add_2
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ y✝ y'✝ : Prequotient F
x✝ : Relation F y✝ y'✝
r_ih : descFunLift F s y✝ = descFunLift F s y'✝
⊢ descFunLift F s (add x✝¹ y✝) = descFunLift F s (add x✝¹ y'✝)
[PROOFSTEP]

| add_2 _ _ _ _ r_ih => dsimp; rw [r_ih]
[GOAL]
case a.add_2
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ y✝ y'✝ : Prequotient F
x✝ : Relation F y✝ y'✝
r_ih : descFunLift F s y✝ = descFunLift F s y'✝
⊢ descFunLift F s (add x✝¹ y✝) = descFunLift F s (add x✝¹ y'✝)
[PROOFSTEP]
dsimp
[GOAL]
case a.add_2
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝¹ y✝ y'✝ : Prequotient F
x✝ : Relation F y✝ y'✝
r_ih : descFunLift F s y✝ = descFunLift F s y'✝
⊢ descFunLift F s x✝¹ + descFunLift F s y✝ = descFunLift F s x✝¹ + descFunLift F s y'✝
[PROOFSTEP]
rw [r_ih]
[GOAL]
case a.zero_add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add zero x✝) = descFunLift F s x✝
[PROOFSTEP]

| zero_add => dsimp; rw [zero_add]
[GOAL]
case a.zero_add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add zero x✝) = descFunLift F s x✝
[PROOFSTEP]
dsimp
[GOAL]
case a.zero_add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ 0 + descFunLift F s x✝ = descFunLift F s x✝
[PROOFSTEP]
rw [zero_add]
[GOAL]
case a.add_zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add x✝ zero) = descFunLift F s x✝
[PROOFSTEP]

| add_zero => dsimp; rw [add_zero]
[GOAL]
case a.add_zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add x✝ zero) = descFunLift F s x✝
[PROOFSTEP]
dsimp
[GOAL]
case a.add_zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s x✝ + 0 = descFunLift F s x✝
[PROOFSTEP]
rw [add_zero]
[GOAL]
case a.add_left_neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add (neg x✝) x✝) = descFunLift F s zero
[PROOFSTEP]

| add_left_neg => dsimp; rw [add_left_neg]
[GOAL]
case a.add_left_neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ descFunLift F s (add (neg x✝) x✝) = descFunLift F s zero
[PROOFSTEP]
dsimp
[GOAL]
case a.add_left_neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ : Prequotient F
⊢ -descFunLift F s x✝ + descFunLift F s x✝ = 0
[PROOFSTEP]
rw [add_left_neg]
[GOAL]
case a.add_comm
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ : Prequotient F
⊢ descFunLift F s (add x✝ y✝) = descFunLift F s (add y✝ x✝)
[PROOFSTEP]

| add_comm => dsimp; rw [add_comm]
[GOAL]
case a.add_comm
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ : Prequotient F
⊢ descFunLift F s (add x✝ y✝) = descFunLift F s (add y✝ x✝)
[PROOFSTEP]
dsimp
[GOAL]
case a.add_comm
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ : Prequotient F
⊢ descFunLift F s x✝ + descFunLift F s y✝ = descFunLift F s y✝ + descFunLift F s x✝
[PROOFSTEP]
rw [add_comm]
[GOAL]
case a.add_assoc
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ z✝ : Prequotient F
⊢ descFunLift F s (add (add x✝ y✝) z✝) = descFunLift F s (add x✝ (add y✝ z✝))
[PROOFSTEP]

| add_assoc => dsimp; rw [add_assoc]
[GOAL]
case a.add_assoc
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ z✝ : Prequotient F
⊢ descFunLift F s (add (add x✝ y✝) z✝) = descFunLift F s (add x✝ (add y✝ z✝))
[PROOFSTEP]
dsimp
[GOAL]
case a.add_assoc
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y x✝ y✝ z✝ : Prequotient F
⊢ descFunLift F s x✝ + descFunLift F s y✝ + descFunLift F s z✝ =
    descFunLift F s x✝ + (descFunLift F s y✝ + descFunLift F s z✝)
[PROOFSTEP]
rw [add_assoc]
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : ↑(colimit F)
x✝¹ x✝ : Prequotient F
⊢ ZeroHom.toFun { toFun := descFun F s, map_zero' := (_ : descFun F s 0 = descFun F s 0) }
      (Quot.mk Setoid.r x✝¹ + Quot.mk Setoid.r x✝) =
    ZeroHom.toFun { toFun := descFun F s, map_zero' := (_ : descFun F s 0 = descFun F s 0) } (Quot.mk Setoid.r x✝¹) +
      ZeroHom.toFun { toFun := descFun F s, map_zero' := (_ : descFun F s 0 = descFun F s 0) } (Quot.mk Setoid.r x✝)
[PROOFSTEP]
dsimp [(· + ·)]
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : ↑(colimit F)
x✝¹ x✝ : Prequotient F
⊢ descFun F s (Add.add (Quot.mk Setoid.r x✝¹) (Quot.mk Setoid.r x✝)) =
    Add.add (descFun F s (Quot.mk Setoid.r x✝¹)) (descFun F s (Quot.mk Setoid.r x✝))
[PROOFSTEP]
rw [← quot_add F]
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
x y : ↑(colimit F)
x✝¹ x✝ : Prequotient F
⊢ descFun F s (Quot.mk Setoid.r (add x✝¹ x✝)) =
    Add.add (descFun F s (Quot.mk Setoid.r x✝¹)) (descFun F s (Quot.mk Setoid.r x✝))
[PROOFSTEP]
rfl
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
⊢ ↑m (Quot.mk Setoid.r x) = ↑((fun s => descMorphism F s) s) (Quot.mk Setoid.r x)
[PROOFSTEP]
change (m : ColimitType F →+ s.pt) _ = (descMorphism F s : ColimitType F →+ s.pt) _
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
⊢ ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
[PROOFSTEP]
induction x using Prequotient.recOn with
| of j x => exact FunLike.congr_fun (w j) x
| zero =>
  dsimp only [quot_zero]
  rw [map_zero, map_zero]
| neg x ih =>
  dsimp only [quot_neg]
  rw [map_neg, map_neg, ih]
| add x y ihx ihy =>
  simp only [quot_add]
  erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
[GOAL]
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
⊢ ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
[PROOFSTEP]
induction x using Prequotient.recOn with
| of j x => exact FunLike.congr_fun (w j) x
| zero =>
  dsimp only [quot_zero]
  rw [map_zero, map_zero]
| neg x ih =>
  dsimp only [quot_neg]
  rw [map_neg, map_neg, ih]
| add x y ihx ihy =>
  simp only [quot_add]
  erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
[GOAL]
case of
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
j : J
x : ↑(F.obj j)
⊢ ↑m (Quot.mk Setoid.r (Prequotient.of j x)) = ↑(descMorphism F s) (Quot.mk Setoid.r (Prequotient.of j x))
[PROOFSTEP]

| of j x => exact FunLike.congr_fun (w j) x
[GOAL]
case of
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
j : J
x : ↑(F.obj j)
⊢ ↑m (Quot.mk Setoid.r (Prequotient.of j x)) = ↑(descMorphism F s) (Quot.mk Setoid.r (Prequotient.of j x))
[PROOFSTEP]
exact FunLike.congr_fun (w j) x
[GOAL]
case zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x : Quot Setoid.r
⊢ ↑m (Quot.mk Setoid.r zero) = ↑(descMorphism F s) (Quot.mk Setoid.r zero)
[PROOFSTEP]

| zero =>
  dsimp only [quot_zero]
  rw [map_zero, map_zero]
[GOAL]
case zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x : Quot Setoid.r
⊢ ↑m (Quot.mk Setoid.r zero) = ↑(descMorphism F s) (Quot.mk Setoid.r zero)
[PROOFSTEP]
dsimp only [quot_zero]
[GOAL]
case zero
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x : Quot Setoid.r
⊢ ↑m 0 = ↑(descMorphism F s) 0
[PROOFSTEP]
rw [map_zero, map_zero]
[GOAL]
case neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
ih : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
⊢ ↑m (Quot.mk Setoid.r (neg x)) = ↑(descMorphism F s) (Quot.mk Setoid.r (neg x))
[PROOFSTEP]

| neg x ih =>
  dsimp only [quot_neg]
  rw [map_neg, map_neg, ih]
[GOAL]
case neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
ih : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
⊢ ↑m (Quot.mk Setoid.r (neg x)) = ↑(descMorphism F s) (Quot.mk Setoid.r (neg x))
[PROOFSTEP]
dsimp only [quot_neg]
[GOAL]
case neg
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x : Prequotient F
ih : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
⊢ ↑m (-Quot.mk Setoid.r x) = ↑(descMorphism F s) (-Quot.mk Setoid.r x)
[PROOFSTEP]
rw [map_neg, map_neg, ih]
[GOAL]
case add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
ihy : ↑m (Quot.mk Setoid.r y) = ↑(descMorphism F s) (Quot.mk Setoid.r y)
⊢ ↑m (Quot.mk Setoid.r (add x y)) = ↑(descMorphism F s) (Quot.mk Setoid.r (add x y))
[PROOFSTEP]

| add x y ihx ihy =>
  simp only [quot_add]
  erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
[GOAL]
case add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
ihy : ↑m (Quot.mk Setoid.r y) = ↑(descMorphism F s) (Quot.mk Setoid.r y)
⊢ ↑m (Quot.mk Setoid.r (add x y)) = ↑(descMorphism F s) (Quot.mk Setoid.r (add x y))
[PROOFSTEP]
simp only [quot_add]
[GOAL]
case add
J : Type v
inst✝ : SmallCategory J
F : J ⥤ AddCommGroupCat
s : Cocone F
m : (colimitCocone F).pt ⟶ s.pt
w : ∀ (j : J), NatTrans.app (colimitCocone F).ι j ≫ m = NatTrans.app s.ι j
x✝ : Quot Setoid.r
x y : Prequotient F
ihx : ↑m (Quot.mk Setoid.r x) = ↑(descMorphism F s) (Quot.mk Setoid.r x)
ihy : ↑m (Quot.mk Setoid.r y) = ↑(descMorphism F s) (Quot.mk Setoid.r y)
⊢ ↑m (Add.add (Quot.mk Setoid.r x) (Quot.mk Setoid.r y)) =
    ↑(descMorphism F s) (Add.add (Quot.mk Setoid.r x) (Quot.mk Setoid.r y))
[PROOFSTEP]
erw [m.map_add, (descMorphism F s).map_add, ihx, ihy]
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ f ≫ mk' (AddMonoidHom.range f) = 0
[PROOFSTEP]
ext x
[GOAL]
case w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑(f ≫ mk' (AddMonoidHom.range f)) x = ↑0 x
[PROOFSTEP]
apply Quotient.sound
[GOAL]
case w.a
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑f x ≈ 0
[PROOFSTEP]
apply leftRel_apply.mpr
[GOAL]
case w.a
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ -↑f x + 0 ∈ AddMonoidHom.range f
[PROOFSTEP]
fconstructor
[GOAL]
case w.a.w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑G
case w.a.h G H : AddCommGroupCat f : G ⟶ H x : ↑G ⊢ ↑f ?w.a.w = -↑f x + 0
[PROOFSTEP]
exact -x
[GOAL]
case w.a.h
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑f (-x) = -↑f x + 0
[PROOFSTEP]
simp only [add_zero, AddMonoidHom.map_neg]
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0
[PROOFSTEP]
rintro _ ⟨x, rfl⟩
[GOAL]
case intro
G H : AddCommGroupCat
f : G ⟶ H
x : ↑G
⊢ ↑(cokernel.π f) (↑f x) = 0
[PROOFSTEP]
exact cokernel.condition_apply f x
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) ≫
      lift (AddMonoidHom.range f) (cokernel.π f) (_ : ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0) =
    𝟙 (cokernel f)
[PROOFSTEP]
refine coequalizer.hom_ext ?_
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ coequalizer.π f 0 ≫
      cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) ≫
        lift (AddMonoidHom.range f) (cokernel.π f) (_ : ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0) =
    coequalizer.π f 0 ≫ 𝟙 (cokernel f)
[PROOFSTEP]
simp only [coequalizer_as_cokernel, cokernel.π_desc_assoc, Category.comp_id]
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ mk' (AddMonoidHom.range f) ≫
      lift (AddMonoidHom.range f) (cokernel.π f) (_ : ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0) =
    cokernel.π f
[PROOFSTEP]
rfl
[GOAL]
G H : AddCommGroupCat
f : G ⟶ H
⊢ lift (AddMonoidHom.range f) (cokernel.π f) (_ : ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0) ≫
      cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0) =
    𝟙 (of (↑H ⧸ AddMonoidHom.range f))
[PROOFSTEP]
ext x
[GOAL]
case w
G H : AddCommGroupCat
f : G ⟶ H
x : ↑(of (↑H ⧸ AddMonoidHom.range f))
⊢ ↑(lift (AddMonoidHom.range f) (cokernel.π f) (_ : ∀ (x : ↑H), x ∈ AddMonoidHom.range f → ↑(cokernel.π f) x = 0) ≫
          cokernel.desc f (mk' (AddMonoidHom.range f)) (_ : f ≫ mk' (AddMonoidHom.range f) = 0))
      x =
    ↑(𝟙 (of (↑H ⧸ AddMonoidHom.range f))) x
[PROOFSTEP]
exact QuotientAddGroup.induction_on x <| cokernel.π_desc_apply f _ _