l3lab/ntp-mathlib huggingface dataset:
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  

Proof state:
case intro.intro
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ s = t

Next tactic:
trans gl
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ s = gl

Next tactic:
apply gl_uniq
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    

Proof state:
case a
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ IsGluing F.val U sf s

Next tactic:
intro i
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    intro i
    

Proof state:
case a
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
i : ι
⊢ (F.val.map (leSupr U i).op) s = sf i

Next tactic:
rfl
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    intro i
    rfl
  · 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ gl = t

Next tactic:
symm
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    intro i
    rfl
  · symm
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ t = gl

Next tactic:
apply gl_uniq
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    intro i
    rfl
  · symm
    apply gl_uniq
    

Proof state:
case a
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
⊢ IsGluing F.val U sf t

Next tactic:
intro i
@[ext]
theorem eq_of_locally_eq (s t : F.1.obj (op (iSup U)))
    (h : ∀ i, F.1.map (Opens.leSupr U i).op s = F.1.map (Opens.leSupr U i).op t) : s = t := by
  let sf : ∀ i : ι, F.1.obj (op (U i)) := fun i => F.1.map (Opens.leSupr U i).op s
  have sf_compatible : IsCompatible _ U sf := by
    intro i j
    simp_rw [← comp_apply, ← F.1.map_comp]
    rfl
  obtain ⟨gl, -, gl_uniq⟩ := F.existsUnique_gluing U sf sf_compatible
  trans gl
  · apply gl_uniq
    intro i
    rfl
  · symm
    apply gl_uniq
    intro i
    

Proof state:
case a
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
s t : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
h : ∀ (i : ι), (F.val.map (leSupr U i).op) s = (F.val.map (leSupr U i).op) t
sf : (i : ι) → (CategoryTheory.forget C).obj (F.val.obj (op (U i))) := fun i => (F.val.map (leSupr U i).op) s
sf_compatible : IsCompatible F.val U sf
gl : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))
gl_uniq : ∀ (y : (CategoryTheory.forget C).obj (F.val.obj (op (iSup U)))), (fun s => IsGluing F.val U sf s) y → y = gl
i : ι
⊢ (F.val.map (leSupr U i).op) t = sf i

Next tactic:
rw [← h]
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
⊢ s = t

Next tactic:
have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
⊢ s = t

Next tactic:
suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
this : (F.val.map (eqToHom (_ : iSup U = V)).op) s = (F.val.map (eqToHom (_ : iSup U = V)).op) t
⊢ s = t

Next tactic:
convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    

Proof state:
case h.e'_2
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
this : (F.val.map (eqToHom (_ : iSup U = V)).op) s = (F.val.map (eqToHom (_ : iSup U = V)).op) t
⊢ s = (F.val.map (eqToHom V_eq_supr_U).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) s)

Next tactic:
rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    

Proof state:
case h.e'_3
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
this : (F.val.map (eqToHom (_ : iSup U = V)).op) s = (F.val.map (eqToHom (_ : iSup U = V)).op) t
⊢ t = (F.val.map (eqToHom V_eq_supr_U).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) t)

Next tactic:
rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
⊢ (F.val.map (eqToHom (_ : iSup U = V)).op) s = (F.val.map (eqToHom (_ : iSup U = V)).op) t

Next tactic:
apply eq_of_locally_eq
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
  apply eq_of_locally_eq
  

Proof state:
case h
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
⊢ ∀ (i : ι),
    (F.val.map (leSupr U i).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) s) =
      (F.val.map (leSupr U i).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) t)

Next tactic:
intro i
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
  apply eq_of_locally_eq
  intro i
  

Proof state:
case h
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
i : ι
⊢ (F.val.map (leSupr U i).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) s) =
    (F.val.map (leSupr U i).op) ((F.val.map (eqToHom (_ : iSup U = V)).op) t)

Next tactic:
rw [← comp_apply, ← comp_apply, ← F.1.map_comp]
/-- In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
which can be more convenient in practice.
-/
theorem eq_of_locally_eq' (V : Opens X) (iUV : ∀ i : ι, U i ⟶ V) (hcover : V ≤ iSup U)
    (s t : F.1.obj (op V)) (h : ∀ i, F.1.map (iUV i).op s = F.1.map (iUV i).op t) : s = t := by
  have V_eq_supr_U : V = iSup U := le_antisymm hcover (iSup_le fun i => (iUV i).le)
  suffices F.1.map (eqToHom V_eq_supr_U.symm).op s = F.1.map (eqToHom V_eq_supr_U.symm).op t by
    convert congr_arg (F.1.map (eqToHom V_eq_supr_U).op) this <;>
    rw [← comp_apply, ← F.1.map_comp, eqToHom_op, eqToHom_op, eqToHom_trans, eqToHom_refl,
      F.1.map_id, id_apply]
  apply eq_of_locally_eq
  intro i
  rw [← comp_apply, ← comp_apply, ← F.1.map_comp]
  

Proof state:
case h
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
V : Opens ↑X
iUV : (i : ι) → U i ⟶ V
hcover : V ≤ iSup U
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h : ∀ (i : ι), (F.val.map (iUV i).op) s = (F.val.map (iUV i).op) t
V_eq_supr_U : V = iSup U
i : ι
⊢ (F.val.map ((eqToHom (_ : iSup U = V)).op ≫ (leSupr U i).op)) s =
    (F.val.map ((eqToHom (_ : iSup U = V)).op ≫ (leSupr U i).op)) t

Next tactic:
convert h i
theorem eq_of_locally_eq₂ {U₁ U₂ V : Opens X} (i₁ : U₁ ⟶ V) (i₂ : U₂ ⟶ V) (hcover : V ≤ U₁ ⊔ U₂)
    (s t : F.1.obj (op V)) (h₁ : F.1.map i₁.op s = F.1.map i₁.op t)
    (h₂ : F.1.map i₂.op s = F.1.map i₂.op t) : s = t := by
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
U₁ U₂ V : Opens ↑X
i₁ : U₁ ⟶ V
i₂ : U₂ ⟶ V
hcover : V ≤ U₁ ⊔ U₂
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h₁ : (F.val.map i₁.op) s = (F.val.map i₁.op) t
h₂ : (F.val.map i₂.op) s = (F.val.map i₂.op) t
⊢ s = t

Next tactic:
classical
    fapply F.eq_of_locally_eq' fun t : ULift Bool => if t.1 then U₁ else U₂
    · exact fun i => if h : i.1 then eqToHom (if_pos h) ≫ i₁ else eqToHom (if_neg h) ≫ i₂
    · refine' le_trans hcover _
      rw [sup_le_iff]
      constructor
      · convert le_iSup (fun t : ULift Bool => if t.1 then U₁ else U₂) (ULift.up true)
      · convert le_iSup (fun t : ULift Bool => if t.1 then U₁ else U₂) (ULift.up false)
    · rintro ⟨_ | _⟩
      any_goals exact h₁
      any_goals exact h₂
theorem eq_of_locally_eq₂ {U₁ U₂ V : Opens X} (i₁ : U₁ ⟶ V) (i₂ : U₂ ⟶ V) (hcover : V ≤ U₁ ⊔ U₂)
    (s t : F.1.obj (op V)) (h₁ : F.1.map i₁.op s = F.1.map i₁.op t)
    (h₂ : F.1.map i₂.op s = F.1.map i₂.op t) : s = t := by
  classical
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
U₁ U₂ V : Opens ↑X
i₁ : U₁ ⟶ V
i₂ : U₂ ⟶ V
hcover : V ≤ U₁ ⊔ U₂
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h₁ : (F.val.map i₁.op) s = (F.val.map i₁.op) t
h₂ : (F.val.map i₂.op) s = (F.val.map i₂.op) t
⊢ s = t

Next tactic:
fapply F.eq_of_locally_eq' fun t : ULift Bool => if t.1 then U₁ else U₂
theorem eq_of_locally_eq₂ {U₁ U₂ V : Opens X} (i₁ : U₁ ⟶ V) (i₂ : U₂ ⟶ V) (hcover : V ≤ U₁ ⊔ U₂)
    (s t : F.1.obj (op V)) (h₁ : F.1.map i₁.op s = F.1.map i₁.op t)
    (h₂ : F.1.map i₂.op s = F.1.map i₂.op t) : s = t := by
  classical
    fapply F.eq_of_locally_eq' fun t : ULift Bool => if t.1 then U₁ else U₂
    · 

Proof state:
case iUV
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : ConcreteCategory C
inst✝² : HasLimits C
inst✝¹ : ReflectsIsomorphisms ConcreteCategory.forget
inst✝ : PreservesLimits ConcreteCategory.forget
X : TopCat
F : Sheaf C X
ι : Type v
U : ι → Opens ↑X
U₁ U₂ V : Opens ↑X
i₁ : U₁ ⟶ V
i₂ : U₂ ⟶ V
hcover : V ≤ U₁ ⊔ U₂
s t : (CategoryTheory.forget C).obj (F.val.obj (op V))
h₁ : (F.val.map i₁.op) s = (F.val.map i₁.op) t
h₂ : (F.val.map i₂.op) s = (F.val.map i₂.op) t
⊢ (i : ULift.{v, 0} Bool) → (if i.down = true then U₁ else U₂) ⟶ V

Next tactic:
exact fun i => if h : i.1 then eqToHom (if_pos h) ≫ i₁ else eqToHom (if_neg h) ≫ i₂