l3lab/ntp-mathlib huggingface dataset:
/-- The subpresheaf as a presheaf. -/
@[simps!]
def Subpresheaf.toPresheaf : Cᵒᵖ ⥤ Type w where
  obj U := G.obj U
  map := @fun U V i x => ⟨F.map i x, G.map i x.prop⟩
  map_id X := by
    ext ⟨x, _⟩
    dsimp
    simp only [FunctorToTypes.map_id_apply]
  map_comp := @fun X Y Z i j => by
    ext ⟨x, _⟩
    

Proof state:
case h.mk.a
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
X Y Z : Cᵒᵖ
i : X ⟶ Y
j : Y ⟶ Z
x : F.obj X
property✝ : x ∈ obj G X
⊢ ↑({ obj := fun U => ↑(obj G U),
            map := fun U V i x => { val := F.map i ↑x, property := (_ : ↑x ∈ F.map i ⁻¹' obj G V) } }.map
        (i ≫ j) { val := x, property := property✝ }) =
    ↑(({ obj := fun U => ↑(obj G U),
                map := fun U V i x => { val := F.map i ↑x, property := (_ : ↑x ∈ F.map i ⁻¹' obj G V) } }.map
            i ≫
          { obj := fun U => ↑(obj G U),
                map := fun U V i x => { val := F.map i ↑x, property := (_ : ↑x ∈ F.map i ⁻¹' obj G V) } }.map
            j)
        { val := x, property := property✝ })

Next tactic:
dsimp
/-- The subpresheaf as a presheaf. -/
@[simps!]
def Subpresheaf.toPresheaf : Cᵒᵖ ⥤ Type w where
  obj U := G.obj U
  map := @fun U V i x => ⟨F.map i x, G.map i x.prop⟩
  map_id X := by
    ext ⟨x, _⟩
    dsimp
    simp only [FunctorToTypes.map_id_apply]
  map_comp := @fun X Y Z i j => by
    ext ⟨x, _⟩
    dsimp
    

Proof state:
case h.mk.a
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
X Y Z : Cᵒᵖ
i : X ⟶ Y
j : Y ⟶ Z
x : F.obj X
property✝ : x ∈ obj G X
⊢ F.map (i ≫ j) x = F.map j (F.map i x)

Next tactic:
simp only [FunctorToTypes.map_comp_apply]
@[reassoc (attr := simp)]
theorem Subpresheaf.homOfLe_ι {G G' : Subpresheaf F} (h : G ≤ G') :
    Subpresheaf.homOfLe h ≫ G'.ι = G.ι := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G✝ G'✝ G G' : Subpresheaf F
h : G ≤ G'
⊢ homOfLe h ≫ ι G' = ι G

Next tactic:
ext
@[reassoc (attr := simp)]
theorem Subpresheaf.homOfLe_ι {G G' : Subpresheaf F} (h : G ≤ G') :
    Subpresheaf.homOfLe h ≫ G'.ι = G.ι := by
  ext
  

Proof state:
case w.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G✝ G'✝ G G' : Subpresheaf F
h : G ≤ G'
x✝ : Cᵒᵖ
a✝ : (toPresheaf G).obj x✝
⊢ (homOfLe h ≫ ι G').app x✝ a✝ = (ι G).app x✝ a✝

Next tactic:
rfl
instance : IsIso (Subpresheaf.ι (⊤ : Subpresheaf F)) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ IsIso (Subpresheaf.ι ⊤)

Next tactic:
refine @NatIso.isIso_of_isIso_app _ _ _ _ _ _ _ ?_
instance : IsIso (Subpresheaf.ι (⊤ : Subpresheaf F)) := by
  refine @NatIso.isIso_of_isIso_app _ _ _ _ _ _ _ ?_
  · 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ ∀ (X : Cᵒᵖ), IsIso ((Subpresheaf.ι ⊤).app X)

Next tactic:
intro X
instance : IsIso (Subpresheaf.ι (⊤ : Subpresheaf F)) := by
  refine @NatIso.isIso_of_isIso_app _ _ _ _ _ _ _ ?_
  · intro X
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
X : Cᵒᵖ
⊢ IsIso ((Subpresheaf.ι ⊤).app X)

Next tactic:
rw [isIso_iff_bijective]
instance : IsIso (Subpresheaf.ι (⊤ : Subpresheaf F)) := by
  refine @NatIso.isIso_of_isIso_app _ _ _ _ _ _ _ ?_
  · intro X
    rw [isIso_iff_bijective]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
X : Cᵒᵖ
⊢ Function.Bijective ((Subpresheaf.ι ⊤).app X)

Next tactic:
exact ⟨Subtype.coe_injective, fun x => ⟨⟨x, _root_.trivial⟩, rfl⟩⟩
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ G = ⊤ ↔ IsIso (ι G)

Next tactic:
constructor
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · 

Proof state:
case mp
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ G = ⊤ → IsIso (ι G)

Next tactic:
rintro rfl
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    

Proof state:
case mp
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G' : Subpresheaf F
⊢ IsIso (ι ⊤)

Next tactic:
infer_instance
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    infer_instance
  · 

Proof state:
case mpr
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ IsIso (ι G) → G = ⊤

Next tactic:
intro H
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    infer_instance
  · intro H
    

Proof state:
case mpr
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
H : IsIso (ι G)
⊢ G = ⊤

Next tactic:
ext U x
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    infer_instance
  · intro H
    ext U x
    

Proof state:
case mpr.obj.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
H : IsIso (ι G)
U : Cᵒᵖ
x : F.obj U
⊢ x ∈ obj G U ↔ x ∈ obj ⊤ U

Next tactic:
apply iff_true_iff.mpr
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    infer_instance
  · intro H
    ext U x
    apply iff_true_iff.mpr
    

Proof state:
case mpr.obj.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
H : IsIso (ι G)
U : Cᵒᵖ
x : F.obj U
⊢ x ∈ obj G U

Next tactic:
rw [← IsIso.inv_hom_id_apply (G.ι.app U) x]
theorem Subpresheaf.eq_top_iff_isIso : G = ⊤ ↔ IsIso G.ι := by
  constructor
  · rintro rfl
    infer_instance
  · intro H
    ext U x
    apply iff_true_iff.mpr
    rw [← IsIso.inv_hom_id_apply (G.ι.app U) x]
    

Proof state:
case mpr.obj.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
H : IsIso (ι G)
U : Cᵒᵖ
x : F.obj U
⊢ ((ι G).app U)
      ((Classical.choose (_ : ∃ inv, (ι G).app U ≫ inv = 𝟙 ((toPresheaf G).obj U) ∧ inv ≫ (ι G).app U = 𝟙 (F.obj U)))
        x) ∈
    obj G U

Next tactic:
exact ((inv (G.ι.app U)) x).2
/-- If the image of a morphism falls in a subpresheaf, then the morphism factors through it. -/
@[simps!]
def Subpresheaf.lift (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) : F' ⟶ G.toPresheaf where
  app U x := ⟨f.app U x, hf U x⟩
  naturality := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
⊢ ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y),
    F'.map f_1 ≫ (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) Y =
      (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) X ≫ (toPresheaf G).map f_1

Next tactic:
have := elementwise_of% f.naturality
/-- If the image of a morphism falls in a subpresheaf, then the morphism factors through it. -/
@[simps!]
def Subpresheaf.lift (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) : F' ⟶ G.toPresheaf where
  app U x := ⟨f.app U x, hf U x⟩
  naturality := by
    have := elementwise_of% f.naturality
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
this : ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y) (x : F'.obj X), f.app Y (F'.map f_1 x) = F.map f_1 (f.app X x)
⊢ ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y),
    F'.map f_1 ≫ (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) Y =
      (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) X ≫ (toPresheaf G).map f_1

Next tactic:
intros
/-- If the image of a morphism falls in a subpresheaf, then the morphism factors through it. -/
@[simps!]
def Subpresheaf.lift (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) : F' ⟶ G.toPresheaf where
  app U x := ⟨f.app U x, hf U x⟩
  naturality := by
    have := elementwise_of% f.naturality
    intros
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
this : ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y) (x : F'.obj X), f.app Y (F'.map f_1 x) = F.map f_1 (f.app X x)
X✝ Y✝ : Cᵒᵖ
f✝ : X✝ ⟶ Y✝
⊢ F'.map f✝ ≫ (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) Y✝ =
    (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) X✝ ≫ (toPresheaf G).map f✝

Next tactic:
refine funext fun x => Subtype.ext ?_
/-- If the image of a morphism falls in a subpresheaf, then the morphism factors through it. -/
@[simps!]
def Subpresheaf.lift (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) : F' ⟶ G.toPresheaf where
  app U x := ⟨f.app U x, hf U x⟩
  naturality := by
    have := elementwise_of% f.naturality
    intros
    refine funext fun x => Subtype.ext ?_
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
this : ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y) (x : F'.obj X), f.app Y (F'.map f_1 x) = F.map f_1 (f.app X x)
X✝ Y✝ : Cᵒᵖ
f✝ : X✝ ⟶ Y✝
x : F'.obj X✝
⊢ ↑((F'.map f✝ ≫ (fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) Y✝) x) =
    ↑(((fun U x => { val := f.app U x, property := (_ : f.app U x ∈ obj G U) }) X✝ ≫ (toPresheaf G).map f✝) x)

Next tactic:
simp only [toPresheaf_obj, types_comp_apply]
/-- If the image of a morphism falls in a subpresheaf, then the morphism factors through it. -/
@[simps!]
def Subpresheaf.lift (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) : F' ⟶ G.toPresheaf where
  app U x := ⟨f.app U x, hf U x⟩
  naturality := by
    have := elementwise_of% f.naturality
    intros
    refine funext fun x => Subtype.ext ?_
    simp only [toPresheaf_obj, types_comp_apply]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
this : ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y) (x : F'.obj X), f.app Y (F'.map f_1 x) = F.map f_1 (f.app X x)
X✝ Y✝ : Cᵒᵖ
f✝ : X✝ ⟶ Y✝
x : F'.obj X✝
⊢ f.app Y✝ (F'.map f✝ x) = ↑((toPresheaf G).map f✝ { val := f.app X✝ x, property := (_ : f.app X✝ x ∈ obj G X✝) })

Next tactic:
exact this _ _
@[reassoc (attr := simp)]
theorem Subpresheaf.lift_ι (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) :
    G.lift f hf ≫ G.ι = f := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
⊢ lift G f hf ≫ ι G = f

Next tactic:
ext
@[reassoc (attr := simp)]
theorem Subpresheaf.lift_ι (f : F' ⟶ F) (hf : ∀ U x, f.app U x ∈ G.obj U) :
    G.lift f hf ≫ G.ι = f := by
  ext
  

Proof state:
case w.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
hf : ∀ (U : Cᵒᵖ) (x : F'.obj U), f.app U x ∈ obj G U
x✝ : Cᵒᵖ
a✝ : F'.obj x✝
⊢ (lift G f hf ≫ ι G).app x✝ a✝ = f.app x✝ a✝

Next tactic:
rfl
/-- Given a subpresheaf `G` of `F`, an `F`-section `s` on `U`, we may define a sieve of `U`
consisting of all `f : V ⟶ U` such that the restriction of `s` along `f` is in `G`. -/
@[simps]
def Subpresheaf.sieveOfSection {U : Cᵒᵖ} (s : F.obj U) : Sieve (unop U) where
  arrows V f := F.map f.op s ∈ G.obj (op V)
  downward_closed := @fun V W i hi j => by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
V W : C
i : V ⟶ U.unop
hi : (fun V f => F.map f.op s ∈ obj G (op V)) V i
j : W ⟶ V
⊢ (fun V f => F.map f.op s ∈ obj G (op V)) W (j ≫ i)

Next tactic:
simp only [op_unop, op_comp, FunctorToTypes.map_comp_apply]
/-- Given a subpresheaf `G` of `F`, an `F`-section `s` on `U`, we may define a sieve of `U`
consisting of all `f : V ⟶ U` such that the restriction of `s` along `f` is in `G`. -/
@[simps]
def Subpresheaf.sieveOfSection {U : Cᵒᵖ} (s : F.obj U) : Sieve (unop U) where
  arrows V f := F.map f.op s ∈ G.obj (op V)
  downward_closed := @fun V W i hi j => by
    simp only [op_unop, op_comp, FunctorToTypes.map_comp_apply]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
V W : C
i : V ⟶ U.unop
hi : (fun V f => F.map f.op s ∈ obj G (op V)) V i
j : W ⟶ V
⊢ F.map j.op (F.map i.op s) ∈ obj G (op W)

Next tactic:
exact G.map _ hi
theorem Subpresheaf.family_of_elements_compatible {U : Cᵒᵖ} (s : F.obj U) :
    (G.familyOfElementsOfSection s).Compatible := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
⊢ Presieve.FamilyOfElements.Compatible (familyOfElementsOfSection G s)

Next tactic:
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
theorem Subpresheaf.family_of_elements_compatible {U : Cᵒᵖ} (s : F.obj U) :
    (G.familyOfElementsOfSection s).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ U.unop
f₂ : Y₂ ⟶ U.unop
h₁ : (sieveOfSection G s).arrows f₁
h₂ : (sieveOfSection G s).arrows f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ (toPresheaf G).map g₁.op (familyOfElementsOfSection G s f₁ h₁) =
    (toPresheaf G).map g₂.op (familyOfElementsOfSection G s f₂ h₂)

Next tactic:
refine Subtype.ext ?_
theorem Subpresheaf.family_of_elements_compatible {U : Cᵒᵖ} (s : F.obj U) :
    (G.familyOfElementsOfSection s).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  refine Subtype.ext ?_ -- port note: `ext1` does not work here
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ U.unop
f₂ : Y₂ ⟶ U.unop
h₁ : (sieveOfSection G s).arrows f₁
h₂ : (sieveOfSection G s).arrows f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ ↑((toPresheaf G).map g₁.op (familyOfElementsOfSection G s f₁ h₁)) =
    ↑((toPresheaf G).map g₂.op (familyOfElementsOfSection G s f₂ h₂))

Next tactic:
change F.map g₁.op (F.map f₁.op s) = F.map g₂.op (F.map f₂.op s)
theorem Subpresheaf.family_of_elements_compatible {U : Cᵒᵖ} (s : F.obj U) :
    (G.familyOfElementsOfSection s).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  refine Subtype.ext ?_ -- port note: `ext1` does not work here
  change F.map g₁.op (F.map f₁.op s) = F.map g₂.op (F.map f₂.op s)
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ U.unop
f₂ : Y₂ ⟶ U.unop
h₁ : (sieveOfSection G s).arrows f₁
h₂ : (sieveOfSection G s).arrows f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ F.map g₁.op (F.map f₁.op s) = F.map g₂.op (F.map f₂.op s)

Next tactic:
rw [← FunctorToTypes.map_comp_apply, ← FunctorToTypes.map_comp_apply, ← op_comp, ← op_comp, e]
/-- The sheafification of a subpresheaf as a subpresheaf.
Note that this is a sheaf only when the whole presheaf is a sheaf. -/
def Subpresheaf.sheafify : Subpresheaf F where
  obj U := { s | G.sieveOfSection s ∈ J (unop U) }
  map := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ ∀ {U V : Cᵒᵖ} (i : U ⟶ V),
    (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) U ⊆
      F.map i ⁻¹' (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) V

Next tactic:
rintro U V i s hs
/-- The sheafification of a subpresheaf as a subpresheaf.
Note that this is a sheaf only when the whole presheaf is a sheaf. -/
def Subpresheaf.sheafify : Subpresheaf F where
  obj U := { s | G.sieveOfSection s ∈ J (unop U) }
  map := by
    rintro U V i s hs
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U V : Cᵒᵖ
i : U ⟶ V
s : F.obj U
hs : s ∈ (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) U
⊢ s ∈ F.map i ⁻¹' (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) V

Next tactic:
refine' J.superset_covering _ (J.pullback_stable i.unop hs)
/-- The sheafification of a subpresheaf as a subpresheaf.
Note that this is a sheaf only when the whole presheaf is a sheaf. -/
def Subpresheaf.sheafify : Subpresheaf F where
  obj U := { s | G.sieveOfSection s ∈ J (unop U) }
  map := by
    rintro U V i s hs
    refine' J.superset_covering _ (J.pullback_stable i.unop hs)
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U V : Cᵒᵖ
i : U ⟶ V
s : F.obj U
hs : s ∈ (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) U
⊢ Sieve.pullback i.unop (sieveOfSection G s) ≤ sieveOfSection G (F.map i s)

Next tactic:
intro _ _ h
/-- The sheafification of a subpresheaf as a subpresheaf.
Note that this is a sheaf only when the whole presheaf is a sheaf. -/
def Subpresheaf.sheafify : Subpresheaf F where
  obj U := { s | G.sieveOfSection s ∈ J (unop U) }
  map := by
    rintro U V i s hs
    refine' J.superset_covering _ (J.pullback_stable i.unop hs)
    intro _ _ h
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U V : Cᵒᵖ
i : U ⟶ V
s : F.obj U
hs : s ∈ (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) U
Y✝ : C
f✝ : Y✝ ⟶ V.unop
h : (Sieve.pullback i.unop (sieveOfSection G s)).arrows f✝
⊢ (sieveOfSection G (F.map i s)).arrows f✝

Next tactic:
dsimp at h ⊢
/-- The sheafification of a subpresheaf as a subpresheaf.
Note that this is a sheaf only when the whole presheaf is a sheaf. -/
def Subpresheaf.sheafify : Subpresheaf F where
  obj U := { s | G.sieveOfSection s ∈ J (unop U) }
  map := by
    rintro U V i s hs
    refine' J.superset_covering _ (J.pullback_stable i.unop hs)
    intro _ _ h
    dsimp at h ⊢
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U V : Cᵒᵖ
i : U ⟶ V
s : F.obj U
hs : s ∈ (fun U => {s | sieveOfSection G s ∈ sieves J U.unop}) U
Y✝ : C
f✝ : Y✝ ⟶ V.unop
h : F.map (i ≫ f✝.op) s ∈ obj G (op Y✝)
⊢ F.map f✝.op (F.map i s) ∈ obj G (op Y✝)

Next tactic:
rwa [← FunctorToTypes.map_comp_apply]
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ G ≤ sheafify J G

Next tactic:
intro U s hs
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  intro U s hs
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj G U
⊢ s ∈ obj (sheafify J G) U

Next tactic:
change _ ∈ J _
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  intro U s hs
  change _ ∈ J _
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj G U
⊢ sieveOfSection G s ∈ sieves J U.unop

Next tactic:
convert J.top_mem U.unop
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  intro U s hs
  change _ ∈ J _
  convert J.top_mem U.unop -- porting note: `U.unop` can not be inferred now
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj G U
⊢ sieveOfSection G s = ⊤

Next tactic:
rw [eq_top_iff]
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  intro U s hs
  change _ ∈ J _
  convert J.top_mem U.unop -- porting note: `U.unop` can not be inferred now
  rw [eq_top_iff]
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj G U
⊢ ⊤ ≤ sieveOfSection G s

Next tactic:
rintro V i -
theorem Subpresheaf.le_sheafify : G ≤ G.sheafify J := by
  intro U s hs
  change _ ∈ J _
  convert J.top_mem U.unop -- porting note: `U.unop` can not be inferred now
  rw [eq_top_iff]
  rintro V i -
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj G U
V : C
i : V ⟶ U.unop
⊢ (sieveOfSection G s).arrows i

Next tactic:
exact G.map i.op hs
theorem Subpresheaf.eq_sheafify (h : Presieve.IsSheaf J F) (hG : Presieve.IsSheaf J G.toPresheaf) :
    G = G.sheafify J := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F
hG : Presieve.IsSheaf J (toPresheaf G)
⊢ G = sheafify J G

Next tactic:
apply (G.le_sheafify J).antisymm
theorem Subpresheaf.eq_sheafify (h : Presieve.IsSheaf J F) (hG : Presieve.IsSheaf J G.toPresheaf) :
    G = G.sheafify J := by
  apply (G.le_sheafify J).antisymm
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F
hG : Presieve.IsSheaf J (toPresheaf G)
⊢ sheafify J G ≤ G

Next tactic:
intro U s hs
theorem Subpresheaf.eq_sheafify (h : Presieve.IsSheaf J F) (hG : Presieve.IsSheaf J G.toPresheaf) :
    G = G.sheafify J := by
  apply (G.le_sheafify J).antisymm
  intro U s hs
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F
hG : Presieve.IsSheaf J (toPresheaf G)
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
⊢ s ∈ obj G U

Next tactic:
suffices ((hG _ hs).amalgamate _ (G.family_of_elements_compatible s)).1 = s by
    rw [← this]
    exact ((hG _ hs).amalgamate _ (G.family_of_elements_compatible s)).2
theorem Subpresheaf.eq_sheafify (h : Presieve.IsSheaf J F) (hG : Presieve.IsSheaf J G.toPresheaf) :
    G = G.sheafify J := by
  apply (G.le_sheafify J).antisymm
  intro U s hs
  suffices ((hG _ hs).amalgamate _ (G.family_of_elements_compatible s)).1 = s by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F
hG : Presieve.IsSheaf J (toPresheaf G)
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
this :
  ↑(Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor (toPresheaf G) (sieveOfSection G s).arrows)
        (familyOfElementsOfSection G s) (_ : Presieve.FamilyOfElements.Compatible (familyOfElementsOfSection G s))) =
    s
⊢ s ∈ obj G U

Next tactic:
rw [← this]
theorem Subpresheaf.eq_sheafify (h : Presieve.IsSheaf J F) (hG : Presieve.IsSheaf J G.toPresheaf) :
    G = G.sheafify J := by
  apply (G.le_sheafify J).antisymm
  intro U s hs
  suffices ((hG _ hs).amalgamate _ (G.family_of_elements_compatible s)).1 = s by
    rw [← this]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F
hG : Presieve.IsSheaf J (toPresheaf G)
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
this :
  ↑(Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor (toPresheaf G) (sieveOfSection G s).arrows)
        (familyOfElementsOfSection G s) (_ : Presieve.FamilyOfElements.Compatible (familyOfElementsOfSection G s))) =
    s
⊢ ↑(Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor (toPresheaf G) (sieveOfSection G s).arrows)
        (familyOfElementsOfSection G s) (_ : Presieve.FamilyOfElements.Compatible (familyOfElementsOfSection G s))) ∈
    obj G U

Next tactic:
exact ((hG _ hs).amalgamate _ (G.family_of_elements_compatible s)).2