l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem stalkSpecializes_refl {C : Type*} [Category C] [Limits.HasColimits C] {X : TopCat}
    (F : X.Presheaf C) (x : X) : F.stalkSpecializes (specializes_refl x) = 𝟙 _ := by
  ext
  

Proof state:
case ih
C✝ : Type u
inst✝³ : Category.{v, u} C✝
inst✝² : HasColimits C✝
X✝ Y Z : TopCat
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasColimits C
X : TopCat
F : Presheaf C X
x : ↑X
U✝ : Opens ↑X
hxU✝ : x ∈ U✝
⊢ germ F { val := x, property := hxU✝ } ≫ stalkSpecializes F (_ : x ⤳ x) =
    germ F { val := x, property := hxU✝ } ≫ 𝟙 (stalk F x)

Next tactic:
simp
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_comp {C : Type*} [Category C] [Limits.HasColimits C] {X : TopCat}
    (F : X.Presheaf C) {x y z : X} (h : x ⤳ y) (h' : y ⤳ z) :
    F.stalkSpecializes h' ≫ F.stalkSpecializes h = F.stalkSpecializes (h.trans h') := by
  

Proof state:
C✝ : Type u
inst✝³ : Category.{v, u} C✝
inst✝² : HasColimits C✝
X✝ Y Z : TopCat
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasColimits C
X : TopCat
F : Presheaf C X
x y z : ↑X
h : x ⤳ y
h' : y ⤳ z
⊢ stalkSpecializes F h' ≫ stalkSpecializes F h = stalkSpecializes F (_ : x ⤳ z)

Next tactic:
ext
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_comp {C : Type*} [Category C] [Limits.HasColimits C] {X : TopCat}
    (F : X.Presheaf C) {x y z : X} (h : x ⤳ y) (h' : y ⤳ z) :
    F.stalkSpecializes h' ≫ F.stalkSpecializes h = F.stalkSpecializes (h.trans h') := by
  ext
  

Proof state:
case ih
C✝ : Type u
inst✝³ : Category.{v, u} C✝
inst✝² : HasColimits C✝
X✝ Y Z : TopCat
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : HasColimits C
X : TopCat
F : Presheaf C X
x y z : ↑X
h : x ⤳ y
h' : y ⤳ z
U✝ : Opens ↑X
hxU✝ : z ∈ U✝
⊢ germ F { val := z, property := hxU✝ } ≫ stalkSpecializes F h' ≫ stalkSpecializes F h =
    germ F { val := z, property := hxU✝ } ≫ stalkSpecializes F (_ : x ⤳ z)

Next tactic:
simp
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x y : X} (h : x ⤳ y) :
    F.stalkSpecializes h ≫ (stalkFunctor C x).map f =
      (stalkFunctor C y).map f ≫ G.stalkSpecializes h := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
F G : Presheaf C X
f : F ⟶ G
x y : ↑X
h : x ⤳ y
⊢ stalkSpecializes F h ≫ (stalkFunctor C x).map f = (stalkFunctor C y).map f ≫ stalkSpecializes G h

Next tactic:
change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x y : X} (h : x ⤳ y) :
    F.stalkSpecializes h ≫ (stalkFunctor C x).map f =
      (stalkFunctor C y).map f ≫ G.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
F G : Presheaf C X
f : F ⟶ G
x y : ↑X
h : x ⤳ y
⊢ stalkSpecializes F h ≫ (stalkFunctor C x).map f = (stalkFunctor C y).map f ≫ stalkSpecializes G h

Next tactic:
ext
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x y : X} (h : x ⤳ y) :
    F.stalkSpecializes h ≫ (stalkFunctor C x).map f =
      (stalkFunctor C y).map f ≫ G.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; 

Proof state:
case w
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
F G : Presheaf C X
f : F ⟶ G
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds y)ᵒᵖ
⊢ colimit.ι (((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op).obj F) j✝ ≫
      stalkSpecializes F h ≫ (stalkFunctor C x).map f =
    colimit.ι (((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op).obj F) j✝ ≫
      (stalkFunctor C y).map f ≫ stalkSpecializes G h

Next tactic:
delta stalkFunctor
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x y : X} (h : x ⤳ y) :
    F.stalkSpecializes h ≫ (stalkFunctor C x).map f =
      (stalkFunctor C y).map f ≫ G.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; delta stalkFunctor; 

Proof state:
case w
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
F G : Presheaf C X
f : F ⟶ G
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds y)ᵒᵖ
⊢ colimit.ι (((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op).obj F) j✝ ≫
      stalkSpecializes F h ≫
        ((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op ⋙ colim).map f =
    colimit.ι (((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op).obj F) j✝ ≫
      ((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op ⋙ colim).map f ≫
        stalkSpecializes G h

Next tactic:
simpa [stalkSpecializes] using by rfl
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem stalkSpecializes_stalkFunctor_map {F G : X.Presheaf C} (f : F ⟶ G) {x y : X} (h : x ⤳ y) :
    F.stalkSpecializes h ≫ (stalkFunctor C x).map f =
      (stalkFunctor C y).map f ≫ G.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; delta stalkFunctor; simpa [stalkSpecializes] using by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
F G : Presheaf C X
f : F ⟶ G
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds y)ᵒᵖ
⊢ f.app (op j✝.unop.obj) ≫
      colimit.ι ((OpenNhds.inclusion x).op ⋙ G) (op { obj := j✝.unop.obj, property := (_ : x ∈ j✝.unop.obj.carrier) }) =
    f.app (op ((OpenNhds.inclusion y).obj j✝.unop)) ≫
      colimit.ι ((OpenNhds.inclusion x).op ⋙ G) (op { obj := j✝.unop.obj, property := (_ : x ∈ j✝.unop.obj.carrier) })

Next tactic:
rfl
@[reassoc, elementwise, simp, nolint simpNF] -- see std4#365 for the simpNF issue
theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) :
    (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x =
      F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
f : X ⟶ Y
F : Presheaf C X
x y : ↑X
h : x ⤳ y
⊢ stalkSpecializes (f _* F) (_ : f x ⤳ f y) ≫ stalkPushforward C f F x = stalkPushforward C f F y ≫ stalkSpecializes F h

Next tactic:
change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
@[reassoc, elementwise, simp, nolint simpNF] -- see std4#365 for the simpNF issue
theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) :
    (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x =
      F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
f : X ⟶ Y
F : Presheaf C X
x y : ↑X
h : x ⤳ y
⊢ stalkSpecializes (f _* F) (_ : f x ⤳ f y) ≫ stalkPushforward C f F x = stalkPushforward C f F y ≫ stalkSpecializes F h

Next tactic:
ext
@[reassoc, elementwise, simp, nolint simpNF] -- see std4#365 for the simpNF issue
theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) :
    (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x =
      F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; 

Proof state:
case w
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
f : X ⟶ Y
F : Presheaf C X
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds (f y))ᵒᵖ
⊢ colimit.ι (((whiskeringLeft (OpenNhds (f y))ᵒᵖ (Opens ↑Y)ᵒᵖ C).obj (OpenNhds.inclusion (f y)).op).obj (f _* F)) j✝ ≫
      stalkSpecializes (f _* F) (_ : f x ⤳ f y) ≫ stalkPushforward C f F x =
    colimit.ι (((whiskeringLeft (OpenNhds (f y))ᵒᵖ (Opens ↑Y)ᵒᵖ C).obj (OpenNhds.inclusion (f y)).op).obj (f _* F)) j✝ ≫
      stalkPushforward C f F y ≫ stalkSpecializes F h

Next tactic:
delta stalkPushforward
@[reassoc, elementwise, simp, nolint simpNF] -- see std4#365 for the simpNF issue
theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) :
    (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x =
      F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; delta stalkPushforward
  

Proof state:
case w
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
f : X ⟶ Y
F : Presheaf C X
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds (f y))ᵒᵖ
⊢ colimit.ι (((whiskeringLeft (OpenNhds (f y))ᵒᵖ (Opens ↑Y)ᵒᵖ C).obj (OpenNhds.inclusion (f y)).op).obj (f _* F)) j✝ ≫
      stalkSpecializes (f _* F) (_ : f x ⤳ f y) ≫
        colim.map (whiskerRight (NatTrans.op (OpenNhds.inclusionMapIso f x).inv) F) ≫
          colimit.pre (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F)
            (OpenNhds.map f x).op =
    colimit.ι (((whiskeringLeft (OpenNhds (f y))ᵒᵖ (Opens ↑Y)ᵒᵖ C).obj (OpenNhds.inclusion (f y)).op).obj (f _* F)) j✝ ≫
      (colim.map (whiskerRight (NatTrans.op (OpenNhds.inclusionMapIso f y).inv) F) ≫
          colimit.pre (((whiskeringLeft (OpenNhds y)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion y).op).obj F)
            (OpenNhds.map f y).op) ≫
        stalkSpecializes F h

Next tactic:
simp only [stalkSpecializes, colimit.ι_desc_assoc, colimit.ι_map_assoc, colimit.ι_pre,
    Category.assoc, colimit.pre_desc, colimit.ι_desc]
@[reassoc, elementwise, simp, nolint simpNF] -- see std4#365 for the simpNF issue
theorem stalkSpecializes_stalkPushforward (f : X ⟶ Y) (F : X.Presheaf C) {x y : X} (h : x ⤳ y) :
    (f _* F).stalkSpecializes (f.map_specializes h) ≫ F.stalkPushforward _ f x =
      F.stalkPushforward _ f y ≫ F.stalkSpecializes h := by
  change (_ : colimit _ ⟶ _) = (_ : colimit _ ⟶ _)
  ext; delta stalkPushforward
  simp only [stalkSpecializes, colimit.ι_desc_assoc, colimit.ι_map_assoc, colimit.ι_pre,
    Category.assoc, colimit.pre_desc, colimit.ι_desc]
  

Proof state:
case w
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : HasColimits C
X Y Z : TopCat
f : X ⟶ Y
F : Presheaf C X
x y : ↑X
h : x ⤳ y
j✝ : (OpenNhds (f y))ᵒᵖ
⊢ (whiskerRight (NatTrans.op (OpenNhds.inclusionMapIso f x).inv) F).app
        (op { obj := j✝.unop.obj, property := (_ : f x ∈ j✝.unop.obj.carrier) }) ≫
      colimit.ι (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F)
        ((OpenNhds.map f x).op.obj (op { obj := j✝.unop.obj, property := (_ : f x ∈ j✝.unop.obj.carrier) })) =
    (whiskerRight (NatTrans.op (OpenNhds.inclusionMapIso f y).inv) F).app j✝ ≫
      (Cocone.whisker (OpenNhds.map f y).op
              { pt := colim.obj (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F),
                ι :=
                  NatTrans.mk fun U =>
                    colimit.ι ((OpenNhds.inclusion x).op ⋙ F)
                      (op { obj := U.unop.obj, property := (_ : x ∈ U.unop.obj.carrier) }) }).ι.app
        j✝

Next tactic:
rfl
/-- The stalks are isomorphic on inseparable points -/
@[simps]
def stalkCongr {X : TopCat} {C : Type*} [Category C] [HasColimits C] (F : X.Presheaf C) {x y : X}
    (e : Inseparable x y) : F.stalk x ≅ F.stalk y :=
  ⟨F.stalkSpecializes e.ge, F.stalkSpecializes e.le, by 

Proof state:
C✝ : Type u
inst✝³ : Category.{v, u} C✝
inst✝² : HasColimits C✝
X✝ Y Z : TopCat
X : TopCat
C : Type u_1
inst✝¹ : Category.{?u.683138, u_1} C
inst✝ : HasColimits C
F : Presheaf C X
x y : ↑X
e : Inseparable x y
⊢ stalkSpecializes F (_ : nhds y ≤ nhds x) ≫ stalkSpecializes F (_ : nhds x ≤ nhds y) = 𝟙 (stalk F x)

Next tactic:
simp
/-- The stalks are isomorphic on inseparable points -/
@[simps]
def stalkCongr {X : TopCat} {C : Type*} [Category C] [HasColimits C] (F : X.Presheaf C) {x y : X}
    (e : Inseparable x y) : F.stalk x ≅ F.stalk y :=
  ⟨F.stalkSpecializes e.ge, F.stalkSpecializes e.le, by simp, by 

Proof state:
C✝ : Type u
inst✝³ : Category.{v, u} C✝
inst✝² : HasColimits C✝
X✝ Y Z : TopCat
X : TopCat
C : Type u_1
inst✝¹ : Category.{?u.683138, u_1} C
inst✝ : HasColimits C
F : Presheaf C X
x y : ↑X
e : Inseparable x y
⊢ stalkSpecializes F (_ : nhds x ≤ nhds y) ≫ stalkSpecializes F (_ : nhds y ≤ nhds x) = 𝟙 (stalk F y)

Next tactic:
simp
theorem germ_ext (F : X.Presheaf C) {U V : Opens X} {x : X} {hxU : x ∈ U} {hxV : x ∈ V}
    (W : Opens X) (hxW : x ∈ W) (iWU : W ⟶ U) (iWV : W ⟶ V) {sU : F.obj (op U)} {sV : F.obj (op V)}
    (ih : F.map iWU.op sU = F.map iWV.op sV) :
      F.germ ⟨x, hxU⟩ sU = F.germ ⟨x, hxV⟩ sV := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasColimits C
X Y Z : TopCat
inst✝ : ConcreteCategory C
F : Presheaf C X
U V : Opens ↑X
x : ↑X
hxU : x ∈ U
hxV : x ∈ V
W : Opens ↑X
hxW : x ∈ W
iWU : W ⟶ U
iWV : W ⟶ V
sU : (forget C).obj (F.obj (op U))
sV : (forget C).obj (F.obj (op V))
ih : (F.map iWU.op) sU = (F.map iWV.op) sV
⊢ (germ F { val := x, property := hxU }) sU = (germ F { val := x, property := hxV }) sV

Next tactic:
erw [← F.germ_res iWU ⟨x, hxW⟩, ← F.germ_res iWV ⟨x, hxW⟩, comp_apply, comp_apply, ih]
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := 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)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
⊢ ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by
  obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
  

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)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
U : (OpenNhds x)ᵒᵖ
s : (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F ⋙ forget C).obj U
e :
  ((forget C).mapCocone
            (colimit.cocone
              (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F))).ι.app
      U s =
    t
⊢ ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
revert s e
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by
  obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
  revert s e
  

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)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
U : (OpenNhds x)ᵒᵖ
⊢ ∀ (s : (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F ⋙ forget C).obj U),
    ((forget C).mapCocone
                (colimit.cocone
                  (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F))).ι.app
          U s =
        t →
      ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
induction U with | h U => ?_
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by
  obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
  revert s e
  induction U with | h U => ?_
  

Proof state:
case intro.intro.h
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasColimits C
X Y Z : TopCat
inst✝¹ : ConcreteCategory C
inst✝ : PreservesFilteredColimits (forget C)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
U : OpenNhds x
⊢ ∀ (s : (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F ⋙ forget C).obj (op U)),
    ((forget C).mapCocone
                (colimit.cocone
                  (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F))).ι.app
          (op U) s =
        t →
      ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
cases' U with V m
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by
  obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
  revert s e
  induction U with | h U => ?_
  cases' U with V m
  

Proof state:
case intro.intro.h.mk
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasColimits C
X Y Z : TopCat
inst✝¹ : ConcreteCategory C
inst✝ : PreservesFilteredColimits (forget C)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
V : Opens ↑X
m : x ∈ V
⊢ ∀
    (s :
      (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F ⋙ forget C).obj
        (op { obj := V, property := m })),
    ((forget C).mapCocone
                (colimit.cocone
                  (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F))).ι.app
          (op { obj := V, property := m }) s =
        t →
      ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
intro s e
/--
For presheaves valued in a concrete category whose forgetful functor preserves filtered colimits,
every element of the stalk is the germ of a section.
-/
theorem germ_exist (F : X.Presheaf C) (x : X) (t : (stalk.{v, u} F x : Type v)) :
    ∃ (U : Opens X) (m : x ∈ U) (s : F.obj (op U)), F.germ ⟨x, m⟩ s = t := by
  obtain ⟨U, s, e⟩ :=
    Types.jointly_surjective.{v, v} _ (isColimitOfPreserves (forget C) (colimit.isColimit _)) t
  revert s e
  induction U with | h U => ?_
  cases' U with V m
  intro s e
  

Proof state:
case intro.intro.h.mk
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasColimits C
X Y Z : TopCat
inst✝¹ : ConcreteCategory C
inst✝ : PreservesFilteredColimits (forget C)
F : Presheaf C X
x : ↑X
t : (forget C).obj (stalk F x)
V : Opens ↑X
m : x ∈ V
s :
  (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F ⋙ forget C).obj
    (op { obj := V, property := m })
e :
  ((forget C).mapCocone
            (colimit.cocone
              (((whiskeringLeft (OpenNhds x)ᵒᵖ (Opens ↑X)ᵒᵖ C).obj (OpenNhds.inclusion x).op).obj F))).ι.app
      (op { obj := V, property := m }) s =
    t
⊢ ∃ U, ∃ (m : x ∈ U), ∃ s, (germ F { val := x, property := m }) s = t

Next tactic:
exact ⟨V, m, s, e⟩
theorem germ_eq (F : X.Presheaf C) {U V : Opens X} (x : X) (mU : x ∈ U) (mV : x ∈ V)
    (s : F.obj (op U)) (t : F.obj (op V)) (h : germ F ⟨x, mU⟩ s = germ F ⟨x, mV⟩ t) :
    ∃ (W : Opens X) (_m : x ∈ W) (iU : W ⟶ U) (iV : W ⟶ V), F.map iU.op s = F.map iV.op t := 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)
F : Presheaf C X
U V : Opens ↑X
x : ↑X
mU : x ∈ U
mV : x ∈ V
s : (forget C).obj (F.obj (op U))
t : (forget C).obj (F.obj (op V))
h : (germ F { val := x, property := mU }) s = (germ F { val := x, property := mV }) t
⊢ ∃ W, ∃ (_ : x ∈ W), ∃ iU iV, (F.map iU.op) s = (F.map iV.op) t

Next tactic:
obtain ⟨W, iU, iV, e⟩ :=
    (Types.FilteredColimit.isColimit_eq_iff.{v, v} _
          (isColimitOfPreserves _ (colimit.isColimit ((OpenNhds.inclusion x).op ⋙ F)))).mp h
theorem germ_eq (F : X.Presheaf C) {U V : Opens X} (x : X) (mU : x ∈ U) (mV : x ∈ V)
    (s : F.obj (op U)) (t : F.obj (op V)) (h : germ F ⟨x, mU⟩ s = germ F ⟨x, mV⟩ t) :
    ∃ (W : Opens X) (_m : x ∈ W) (iU : W ⟶ U) (iV : W ⟶ V), F.map iU.op s = F.map iV.op t := by
  obtain ⟨W, iU, iV, e⟩ :=
    (Types.FilteredColimit.isColimit_eq_iff.{v, v} _
          (isColimitOfPreserves _ (colimit.isColimit ((OpenNhds.inclusion x).op ⋙ F)))).mp h
  

Proof state:
case intro.intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasColimits C
X Y Z : TopCat
inst✝¹ : ConcreteCategory C
inst✝ : PreservesFilteredColimits (forget C)
F : Presheaf C X
U V : Opens ↑X
x : ↑X
mU : x ∈ U
mV : x ∈ V
s : (forget C).obj (F.obj (op U))
t : (forget C).obj (F.obj (op V))
h : (germ F { val := x, property := mU }) s = (germ F { val := x, property := mV }) t
W : (OpenNhds x)ᵒᵖ
iU : op { obj := U, property := (_ : ↑{ val := x, property := mU } ∈ U) } ⟶ W
iV : op { obj := V, property := (_ : ↑{ val := x, property := mV } ∈ V) } ⟶ W
e : (((OpenNhds.inclusion x).op ⋙ F) ⋙ forget C).map iU s = (((OpenNhds.inclusion x).op ⋙ F) ⋙ forget C).map iV t
⊢ ∃ W, ∃ (_ : x ∈ W), ∃ iU iV, (F.map iU.op) s = (F.map iV.op) t

Next tactic:
exact ⟨(unop W).1, (unop W).2, iU.unop, iV.unop, e⟩
theorem stalkFunctor_map_injective_of_app_injective {F G : Presheaf C X} (f : F ⟶ G)
    (h : ∀ U : Opens X, Function.Injective (f.app (op U))) (x : X) :
    Function.Injective ((stalkFunctor C x).map f) := fun s t hst => 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)
F G : Presheaf C X
f : F ⟶ G
h : ∀ (U : Opens ↑X), Function.Injective ⇑(f.app (op U))
x : ↑X
s t : (forget C).obj ((stalkFunctor C x).obj F)
hst : ((stalkFunctor C x).map f) s = ((stalkFunctor C x).map f) t
⊢ s = t

Next tactic:
rcases germ_exist F x s with ⟨U₁, hxU₁, s, rfl⟩
theorem stalkFunctor_map_injective_of_app_injective {F G : Presheaf C X} (f : F ⟶ G)
    (h : ∀ U : Opens X, Function.Injective (f.app (op U))) (x : X) :
    Function.Injective ((stalkFunctor C x).map f) := fun s t hst => by
  rcases germ_exist F x s with ⟨U₁, hxU₁, s, rfl⟩
  

Proof state:
case intro.intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasColimits C
X Y Z : TopCat
inst✝¹ : ConcreteCategory C
inst✝ : PreservesFilteredColimits (forget C)
F G : Presheaf C X
f : F ⟶ G
h : ∀ (U : Opens ↑X), Function.Injective ⇑(f.app (op U))
x : ↑X
t : (forget C).obj ((stalkFunctor C x).obj F)
U₁ : Opens ↑X
hxU₁ : x ∈ U₁
s : (forget C).obj (F.obj (op U₁))
hst : ((stalkFunctor C x).map f) ((germ F { val := x, property := hxU₁ }) s) = ((stalkFunctor C x).map f) t
⊢ (germ F { val := x, property := hxU₁ }) s = t

Next tactic:
rcases germ_exist F x t with ⟨U₂, hxU₂, t, rfl⟩