l3lab/ntp-mathlib huggingface dataset:
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
⊢ ∃ a, (f.val.app (op U)) a = t

Next tactic:
choose V mV iVU sf heq using hsurj t
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
⊢ ∃ a, (f.val.app (op U)) a = t

Next tactic:
have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
⊢ U ≤ iSup V

Next tactic:
intro x hxU
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
x : ↑X
hxU : x ∈ ↑U
⊢ x ∈ ↑(iSup V)

Next tactic:
simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
x : ↑X
hxU : x ∈ ↑U
⊢ ∃ i, x ∈ V i

Next tactic:
exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
⊢ ∃ a, (f.val.app (op U)) a = t

Next tactic:
suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · use s
      apply G.eq_of_locally_eq' V U iVU V_cover
      intro x
      rw [← comp_apply, ← f.1.naturality, comp_apply, s_spec, heq]
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
this : IsCompatible F.val V sf
⊢ ∃ a, (f.val.app (op U)) a = t

Next tactic:
obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · 

Proof state:
case intro.intro
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
this : IsCompatible F.val V sf
s : (forget C).obj (F.val.obj (op U))
s_spec : ∀ (i : ↥U), (F.val.map (iVU i).op) s = sf i
⊢ ∃ a, (f.val.app (op U)) a = t

Next tactic:
use s
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · use s
      

Proof state:
case h
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
this : IsCompatible F.val V sf
s : (forget C).obj (F.val.obj (op U))
s_spec : ∀ (i : ↥U), (F.val.map (iVU i).op) s = sf i
⊢ (f.val.app (op U)) s = t

Next tactic:
apply G.eq_of_locally_eq' V U iVU V_cover
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · use s
      apply G.eq_of_locally_eq' V U iVU V_cover
      

Proof state:
case h.h
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
this : IsCompatible F.val V sf
s : (forget C).obj (F.val.obj (op U))
s_spec : ∀ (i : ↥U), (F.val.map (iVU i).op) s = sf i
⊢ ∀ (i : ↥U), (G.val.map (iVU i).op) ((f.val.app (op U)) s) = (G.val.map (iVU i).op) t

Next tactic:
intro x
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · use s
      apply G.eq_of_locally_eq' V U iVU V_cover
      intro x
      

Proof state:
case h.h
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
this : IsCompatible F.val V sf
s : (forget C).obj (F.val.obj (op U))
s_spec : ∀ (i : ↥U), (F.val.map (iVU i).op) s = sf i
x : ↥U
⊢ (G.val.map (iVU x).op) ((f.val.app (op U)) s) = (G.val.map (iVU x).op) t

Next tactic:
rw [← comp_apply, ← f.1.naturality, comp_apply, s_spec, heq]
/-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
We claim that it suffices to find preimages *locally*. That is, for each `x : U` we construct
a neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
agree on `V`. -/
theorem app_surjective_of_injective_of_locally_surjective {F G : Sheaf C X} (f : F ⟶ G)
    (U : Opens X) (hinj : ∀ x : U, Function.Injective ((stalkFunctor C x.1).map f.1))
    (hsurj : ∀ (t) (x : U), ∃ (V : Opens X) (_ : x.1 ∈ V) (iVU : V ⟶ U) (s : F.1.obj (op V)),
          f.1.app (op V) s = G.1.map iVU.op t) :
    Function.Surjective (f.1.app (op U)) := by
  intro t
  -- We use the axiom of choice to pick around each point `x` an open neighborhood `V` and a
  -- preimage under `f` on `V`.
  choose V mV iVU sf heq using hsurj t
  -- These neighborhoods clearly cover all of `U`.
  have V_cover : U ≤ iSup V := by
    intro x hxU
    simp only [Opens.coe_iSup, Set.mem_iUnion, SetLike.mem_coe]
    exact ⟨⟨x, hxU⟩, mV ⟨x, hxU⟩⟩
  suffices IsCompatible F.val V sf by
    -- Since `F` is a sheaf, we can glue all the local preimages together to get a global preimage.
    obtain ⟨s, s_spec, -⟩ := F.existsUnique_gluing' V U iVU V_cover sf this
    · use s
      apply G.eq_of_locally_eq' V U iVU V_cover
      intro x
      rw [← comp_apply, ← f.1.naturality, comp_apply, s_spec, heq]
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : HasColimits C
X Y Z : TopCat
inst✝⁴ : ConcreteCategory C
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasLimits C
inst✝¹ : PreservesLimits (forget C)
inst✝ : ReflectsIsomorphisms (forget C)
F G : Sheaf C X
f : F ⟶ G
U : Opens ↑X
hinj : ∀ (x : ↥U), Function.Injective ⇑((stalkFunctor C ↑x).map f.val)
hsurj :
  ∀ (t : (forget C).obj (G.val.obj (op U))) (x : ↥U),
    ∃ V, ∃ (_ : ↑x ∈ V), ∃ iVU s, (f.val.app (op V)) s = (G.val.map iVU.op) t
t : (forget C).obj (G.val.obj (op U))
V : ↥U → Opens ↑X
mV : ∀ (x : ↥U), ↑x ∈ V x
iVU : (x : ↥U) → V x ⟶ U
sf : (x : ↥U) → (forget C).obj (F.val.obj (op (V x)))
heq : ∀ (x : ↥U), (f.val.app (op (V x))) (sf x) = (G.val.map (iVU x).op) t
V_cover : U ≤ iSup V
⊢ IsCompatible F.val V sf

Next tactic:
intro x y