l3lab/ntp-mathlib huggingface dataset:
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    

Proof state:
case h
D : GlueData
i : D.J
a : ↑(GlueData.U D.toGlueData i)
j : D.J
b : ↑(GlueData.U D.toGlueData j)
k : D.J
c : ↑(GlueData.U D.toGlueData k)
x : ↑(GlueData.V D.toGlueData ({ fst := i, snd := a }.fst, { fst := j, snd := b }.fst))
e₁ : (GlueData.f D.toGlueData { fst := i, snd := a }.fst { fst := j, snd := b }.fst) x = { fst := i, snd := a }.snd
e₂ :
  (GlueData.f D.toGlueData { fst := j, snd := b }.fst { fst := i, snd := a }.fst)
      ((GlueData.t D.toGlueData { fst := i, snd := a }.fst { fst := j, snd := b }.fst) x) =
    { fst := j, snd := b }.snd
y : ↑(GlueData.V D.toGlueData ({ fst := j, snd := b }.fst, { fst := k, snd := c }.fst))
e₃ : (GlueData.f D.toGlueData { fst := j, snd := b }.fst { fst := k, snd := c }.fst) y = { fst := j, snd := b }.snd
e₄ :
  (GlueData.f D.toGlueData { fst := k, snd := c }.fst { fst := j, snd := b }.fst)
      ((GlueData.t D.toGlueData { fst := j, snd := b }.fst { fst := k, snd := c }.fst) y) =
    { fst := k, snd := c }.snd
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
eq₁ : (GlueData.t D.toGlueData j i) (pullback.fst z) = x
eq₂ : pullback.snd z = y
⊢ (GlueData.f D.toGlueData { fst := i, snd := a }.fst { fst := k, snd := c }.fst)
        (pullback.fst ((GlueData.t' D.toGlueData j i k) z)) =
      { fst := i, snd := a }.snd ∧
    (GlueData.f D.toGlueData { fst := k, snd := c }.fst { fst := i, snd := a }.fst)
        ((GlueData.t D.toGlueData { fst := i, snd := a }.fst { fst := k, snd := c }.fst)
          (pullback.fst ((GlueData.t' D.toGlueData j i k) z))) =
      { fst := k, snd := c }.snd

Next tactic:
dsimp only at *
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    

Proof state:
case h
D : GlueData
i : D.J
a : ↑(GlueData.U D.toGlueData i)
j : D.J
b : ↑(GlueData.U D.toGlueData j)
k : D.J
c : ↑(GlueData.U D.toGlueData k)
x : ↑(GlueData.V D.toGlueData ({ fst := i, snd := a }.fst, { fst := j, snd := b }.fst))
e₁ : (GlueData.f D.toGlueData i j) x = a
e₂ : (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) x) = b
y : ↑(GlueData.V D.toGlueData ({ fst := j, snd := b }.fst, { fst := k, snd := c }.fst))
e₃ : (GlueData.f D.toGlueData j k) y = b
e₄ : (GlueData.f D.toGlueData k j) ((GlueData.t D.toGlueData j k) y) = c
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
eq₁ : (GlueData.t D.toGlueData j i) (pullback.fst z) = x
eq₂ : pullback.snd z = y
⊢ (GlueData.f D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z)) = a ∧
    (GlueData.f D.toGlueData k i) ((GlueData.t D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z))) =
      c

Next tactic:
substs eq₁ eq₂ e₁ e₃ e₄
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    

Proof state:
case h
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
⊢ (GlueData.f D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z)) =
      (GlueData.f D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z)) ∧
    (GlueData.f D.toGlueData k i) ((GlueData.t D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z))) =
      (GlueData.f D.toGlueData k j) ((GlueData.t D.toGlueData j k) (pullback.snd z))

Next tactic:
have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      

Proof state:
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
⊢ GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j

Next tactic:
rw [← 𝖣.t_fac_assoc]
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; 

Proof state:
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
⊢ GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    GlueData.t' D.toGlueData j i k ≫ pullback.snd ≫ GlueData.f D.toGlueData i j

Next tactic:
congr 1
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; 

Proof state:
case e_a
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
⊢ pullback.fst ≫ GlueData.f D.toGlueData i k = pullback.snd ≫ GlueData.f D.toGlueData i j

Next tactic:
exact pullback.condition
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    

Proof state:
case h
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
⊢ (GlueData.f D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z)) =
      (GlueData.f D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z)) ∧
    (GlueData.f D.toGlueData k i) ((GlueData.t D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z))) =
      (GlueData.f D.toGlueData k j) ((GlueData.t D.toGlueData j k) (pullback.snd z))

Next tactic:
have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      rw [← 𝖣.t_fac_assoc]
      apply @Epi.left_cancellation _ _ _ _ (D.t' k j i)
      rw [𝖣.cocycle_assoc, 𝖣.t_fac_assoc, 𝖣.t_inv_assoc]
      exact pullback.condition.symm
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      

Proof state:
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
⊢ GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.t D.toGlueData i k ≫ GlueData.f D.toGlueData k i =
    pullback.snd ≫ GlueData.t D.toGlueData j k ≫ GlueData.f D.toGlueData k j

Next tactic:
rw [← 𝖣.t_fac_assoc]
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      rw [← 𝖣.t_fac_assoc]
      

Proof state:
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
⊢ GlueData.t' D.toGlueData j i k ≫ GlueData.t' D.toGlueData i k j ≫ pullback.snd ≫ GlueData.f D.toGlueData k i =
    pullback.snd ≫ GlueData.t D.toGlueData j k ≫ GlueData.f D.toGlueData k j

Next tactic:
apply @Epi.left_cancellation _ _ _ _ (D.t' k j i)
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      rw [← 𝖣.t_fac_assoc]
      apply @Epi.left_cancellation _ _ _ _ (D.t' k j i)
      

Proof state:
case a
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
⊢ GlueData.t' D.toGlueData k j i ≫
      GlueData.t' D.toGlueData j i k ≫ GlueData.t' D.toGlueData i k j ≫ pullback.snd ≫ GlueData.f D.toGlueData k i =
    GlueData.t' D.toGlueData k j i ≫ pullback.snd ≫ GlueData.t D.toGlueData j k ≫ GlueData.f D.toGlueData k j

Next tactic:
rw [𝖣.cocycle_assoc, 𝖣.t_fac_assoc, 𝖣.t_inv_assoc]
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      rw [← 𝖣.t_fac_assoc]
      apply @Epi.left_cancellation _ _ _ _ (D.t' k j i)
      rw [𝖣.cocycle_assoc, 𝖣.t_fac_assoc, 𝖣.t_inv_assoc]
      

Proof state:
case a
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
⊢ pullback.snd ≫ GlueData.f D.toGlueData k i = pullback.fst ≫ GlueData.f D.toGlueData k j

Next tactic:
exact pullback.condition.symm
theorem rel_equiv : Equivalence D.Rel :=
  ⟨fun x => Or.inl (refl x), by
    rintro a b (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩)
    exacts [Or.inl rfl, Or.inr ⟨D.t _ _ x, by simp [e₁, e₂]⟩], by
    rintro ⟨i, a⟩ ⟨j, b⟩ ⟨k, c⟩ (⟨⟨⟩⟩ | ⟨x, e₁, e₂⟩); exact id
    rintro (⟨⟨⟩⟩ | ⟨y, e₃, e₄⟩); exact Or.inr ⟨x, e₁, e₂⟩
    let z := (pullbackIsoProdSubtype (D.f j i) (D.f j k)).inv ⟨⟨_, _⟩, e₂.trans e₃.symm⟩
    have eq₁ : (D.t j i) ((pullback.fst : _ /-(D.f j k)-/ ⟶ D.V (j, i)) z) = x := by simp
    have eq₂ : (pullback.snd : _ ⟶ D.V _) z = y := pullbackIsoProdSubtype_inv_snd_apply _ _ _
    clear_value z
    right
    use (pullback.fst : _ ⟶ D.V (i, k)) (D.t' _ _ _ z)
    dsimp only at *
    substs eq₁ eq₂ e₁ e₃ e₄
    have h₁ : D.t' j i k ≫ pullback.fst ≫ D.f i k = pullback.fst ≫ D.t j i ≫ D.f i j := by
      rw [← 𝖣.t_fac_assoc]; congr 1; exact pullback.condition
    have h₂ : D.t' j i k ≫ pullback.fst ≫ D.t i k ≫ D.f k i = pullback.snd ≫ D.t j k ≫ D.f k j := by
      rw [← 𝖣.t_fac_assoc]
      apply @Epi.left_cancellation _ _ _ _ (D.t' k j i)
      rw [𝖣.cocycle_assoc, 𝖣.t_fac_assoc, 𝖣.t_inv_assoc]
      exact pullback.condition.symm
    

Proof state:
case h
D : GlueData
i j k : D.J
z : (forget TopCat).obj (pullback (GlueData.f D.toGlueData j i) (GlueData.f D.toGlueData j k))
e₂ :
  (GlueData.f D.toGlueData j i) ((GlueData.t D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z))) =
    (GlueData.f D.toGlueData j k) (pullback.snd z)
h₁ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.f D.toGlueData i k =
    pullback.fst ≫ GlueData.t D.toGlueData j i ≫ GlueData.f D.toGlueData i j
h₂ :
  GlueData.t' D.toGlueData j i k ≫ pullback.fst ≫ GlueData.t D.toGlueData i k ≫ GlueData.f D.toGlueData k i =
    pullback.snd ≫ GlueData.t D.toGlueData j k ≫ GlueData.f D.toGlueData k j
⊢ (GlueData.f D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z)) =
      (GlueData.f D.toGlueData i j) ((GlueData.t D.toGlueData j i) (pullback.fst z)) ∧
    (GlueData.f D.toGlueData k i) ((GlueData.t D.toGlueData i k) (pullback.fst ((GlueData.t' D.toGlueData j i k) z))) =
      (GlueData.f D.toGlueData k j) ((GlueData.t D.toGlueData j k) (pullback.snd z))

Next tactic:
exact ⟨ContinuousMap.congr_fun h₁ z, ContinuousMap.congr_fun h₂ z⟩
theorem eqvGen_of_π_eq
    -- Porting note: was `{x y : ∐ D.U} (h : 𝖣.π x = 𝖣.π y)`
    {x y : sigmaObj (β := D.toGlueData.J) (C := TopCat) D.toGlueData.U}
    (h : 𝖣.π x = 𝖣.π y) :
    EqvGen
      -- Porting note: was (Types.CoequalizerRel 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      (Types.CoequalizerRel
        (X := sigmaObj (β := D.toGlueData.diagram.L) (C := TopCat) (D.toGlueData.diagram).left)
        (Y := sigmaObj (β := D.toGlueData.diagram.R) (C := TopCat) (D.toGlueData.diagram).right)
        𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      x y := by
  

Proof state:
D : GlueData
x y : ↑(∐ D.U)
h : (GlueData.π D.toGlueData) x = (GlueData.π D.toGlueData) y
⊢ EqvGen
    (Types.CoequalizerRel ⇑(MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
      ⇑(MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData)))
    x y

Next tactic:
delta GlueData.π Multicoequalizer.sigmaπ at h
theorem eqvGen_of_π_eq
    -- Porting note: was `{x y : ∐ D.U} (h : 𝖣.π x = 𝖣.π y)`
    {x y : sigmaObj (β := D.toGlueData.J) (C := TopCat) D.toGlueData.U}
    (h : 𝖣.π x = 𝖣.π y) :
    EqvGen
      -- Porting note: was (Types.CoequalizerRel 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      (Types.CoequalizerRel
        (X := sigmaObj (β := D.toGlueData.diagram.L) (C := TopCat) (D.toGlueData.diagram).left)
        (Y := sigmaObj (β := D.toGlueData.diagram.R) (C := TopCat) (D.toGlueData.diagram).right)
        𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      x y := by
  delta GlueData.π Multicoequalizer.sigmaπ at h
  -- Porting note: inlined `inferInstance` instead of leaving as a side goal.
  

Proof state:
D : GlueData
x y : ↑(∐ D.U)
h :
  (coequalizer.π (MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
          (MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData)) ≫
        (Multicoequalizer.isoCoequalizer (GlueData.diagram D.toGlueData)).inv)
      x =
    (coequalizer.π (MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
          (MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData)) ≫
        (Multicoequalizer.isoCoequalizer (GlueData.diagram D.toGlueData)).inv)
      y
⊢ EqvGen
    (Types.CoequalizerRel ⇑(MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
      ⇑(MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData)))
    x y

Next tactic:
replace h := (TopCat.mono_iff_injective (Multicoequalizer.isoCoequalizer 𝖣.diagram).inv).mp
    inferInstance h
theorem eqvGen_of_π_eq
    -- Porting note: was `{x y : ∐ D.U} (h : 𝖣.π x = 𝖣.π y)`
    {x y : sigmaObj (β := D.toGlueData.J) (C := TopCat) D.toGlueData.U}
    (h : 𝖣.π x = 𝖣.π y) :
    EqvGen
      -- Porting note: was (Types.CoequalizerRel 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      (Types.CoequalizerRel
        (X := sigmaObj (β := D.toGlueData.diagram.L) (C := TopCat) (D.toGlueData.diagram).left)
        (Y := sigmaObj (β := D.toGlueData.diagram.R) (C := TopCat) (D.toGlueData.diagram).right)
        𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap)
      x y := by
  delta GlueData.π Multicoequalizer.sigmaπ at h
  -- Porting note: inlined `inferInstance` instead of leaving as a side goal.
  replace h := (TopCat.mono_iff_injective (Multicoequalizer.isoCoequalizer 𝖣.diagram).inv).mp
    inferInstance h
  

Proof state:
D : GlueData
x y : ↑(∐ D.U)
h :
  (coequalizer.π (MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
          (MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData))).1
      x =
    (coequalizer.π (MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
          (MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData))).1
      y
⊢ EqvGen
    (Types.CoequalizerRel ⇑(MultispanIndex.fstSigmaMap (GlueData.diagram D.toGlueData))
      ⇑(MultispanIndex.sndSigmaMap (GlueData.diagram D.toGlueData)))
    x y

Next tactic:
let diagram := parallelPair 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap ⋙ forget _