l3lab/ntp-mathlib huggingface dataset:
/-- If `E` is a cone of shape `K` of sheaves, which is a limit on the level of presheaves,
this definition shows that the limit presheaf satisfies the multifork variant of the sheaf
condition, at a given covering `W`.

This is used below in `isSheaf_of_isLimit` to show that the limit presheaf is indeed a sheaf.
-/
def isLimitMultiforkOfIsLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D))
    (hE : IsLimit E) (X : C) (W : J.Cover X) : IsLimit (W.multifork E.pt) :=
  Multifork.IsLimit.mk _
    (fun S => (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).lift <|
      multiforkEvaluationCone F E X W S)
    (by
      intro S i
      apply (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op i.Y)) hE).hom_ext
      intro k
      dsimp [Multifork.ofι]
      erw [Category.assoc, (E.π.app k).naturality]
      dsimp
      rw [← Category.assoc]
      erw [(isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).fac
        (multiforkEvaluationCone F E X W S)]
      dsimp [multiforkEvaluationCone, Presheaf.isLimitOfIsSheaf]
      erw [Presheaf.IsSheaf.amalgamate_map]
      rfl)
    (by
      intro S m hm
      apply (isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).hom_ext
      intro k
      dsimp
      erw [(isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).fac]
      apply Presheaf.IsSheaf.hom_ext (F.obj k).2 W
      intro i
      dsimp only [multiforkEvaluationCone, Presheaf.isLimitOfIsSheaf]
      rw [(F.obj k).cond.amalgamate_map]
      dsimp [Multifork.ofι]
      change _ = S.ι i ≫ _
      erw [← hm, Category.assoc, ← (E.π.app k).naturality, Category.assoc]
      

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
m : S.pt ⟶ (GrothendieckTopology.Cover.multifork W E.pt).pt
hm :
  ∀ (i : (GrothendieckTopology.Cover.index W E.pt).L),
    m ≫ Multifork.ι (GrothendieckTopology.Cover.multifork W E.pt) i = Multifork.ι S i
k : K
i : GrothendieckTopology.Cover.Arrow W
⊢ m ≫ (((Functor.const K).obj E.pt).obj k).map i.f.op ≫ (E.π.app k).app (op i.Y) =
    m ≫ Multifork.ι (GrothendieckTopology.Cover.multifork W E.pt) i ≫ (E.π.app k).app (op i.Y)

Next tactic:
rfl
/-- If `E` is a cone which is a limit on the level of presheaves,
then the limit presheaf is again a sheaf.

This is used to show that the forgetful functor from sheaves to presheaves creates limits.
-/
theorem isSheaf_of_isLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D))
    (hE : IsLimit E) : Presheaf.IsSheaf J E.pt := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
⊢ Presheaf.IsSheaf J E.pt

Next tactic:
rw [Presheaf.isSheaf_iff_multifork]
/-- If `E` is a cone which is a limit on the level of presheaves,
then the limit presheaf is again a sheaf.

This is used to show that the forgetful functor from sheaves to presheaves creates limits.
-/
theorem isSheaf_of_isLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D))
    (hE : IsLimit E) : Presheaf.IsSheaf J E.pt := by
  rw [Presheaf.isSheaf_iff_multifork]
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
⊢ ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S E.pt))

Next tactic:
intro X S
/-- If `E` is a cone which is a limit on the level of presheaves,
then the limit presheaf is again a sheaf.

This is used to show that the forgetful functor from sheaves to presheaves creates limits.
-/
theorem isSheaf_of_isLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D))
    (hE : IsLimit E) : Presheaf.IsSheaf J E.pt := by
  rw [Presheaf.isSheaf_iff_multifork]
  intro X S
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
X : C
S : GrothendieckTopology.Cover J X
⊢ Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S E.pt))

Next tactic:
exact ⟨isLimitMultiforkOfIsLimit _ _ hE _ _⟩
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
j : K
⊢ ((sheafToPresheaf J D).mapCone
            { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
              π := NatTrans.mk fun t => { val := E.π.app t } }).π.app
      j =
    (eqToIso
          (_ :
            ((sheafToPresheaf J D).mapCone
                  { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                    π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
              ((sheafToPresheaf J D).mapCone
                  { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                    π := NatTrans.mk fun t => { val := E.π.app t } }).pt)).hom ≫
      E.π.app j

Next tactic:
dsimp
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        dsimp
        

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
j : K
⊢ E.π.app j = 𝟙 E.pt ≫ E.π.app j

Next tactic:
simp
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        dsimp
        simp
      makesLimit :=
        { lift := fun S => ⟨hE.lift ((sheafToPresheaf J D).mapCone S)⟩
          fac := fun S j => by
            

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
S : Cone F
j : K
⊢ (fun S => { val := IsLimit.lift hE ((sheafToPresheaf J D).mapCone S) }) S ≫
      {
                liftedCone :=
                  { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                    π := NatTrans.mk fun t => { val := E.π.app t } },
                validLift :=
                  Cones.ext
                    (eqToIso
                      (_ :
                        ((sheafToPresheaf J D).mapCone
                              { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                          ((sheafToPresheaf J D).mapCone
                              { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.π.app
        j =
    S.π.app j

Next tactic:
ext1
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        dsimp
        simp
      makesLimit :=
        { lift := fun S => ⟨hE.lift ((sheafToPresheaf J D).mapCone S)⟩
          fac := fun S j => by
            ext1
            

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
S : Cone F
j : K
⊢ ((fun S => { val := IsLimit.lift hE ((sheafToPresheaf J D).mapCone S) }) S ≫
        {
                  liftedCone :=
                    { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                      π := NatTrans.mk fun t => { val := E.π.app t } },
                  validLift :=
                    Cones.ext
                      (eqToIso
                        (_ :
                          ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                            ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.π.app
          j).val =
    (S.π.app j).val

Next tactic:
apply hE.fac ((sheafToPresheaf J D).mapCone S) j
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        dsimp
        simp
      makesLimit :=
        { lift := fun S => ⟨hE.lift ((sheafToPresheaf J D).mapCone S)⟩
          fac := fun S j => by
            ext1
            apply hE.fac ((sheafToPresheaf J D).mapCone S) j
          uniq := fun S m hm => by
            

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
S : Cone F
m :
  S.pt ⟶
    {
          liftedCone :=
            { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
              π := NatTrans.mk fun t => { val := E.π.app t } },
          validLift :=
            Cones.ext
              (eqToIso
                (_ :
                  ((sheafToPresheaf J D).mapCone
                        { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                          π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                    ((sheafToPresheaf J D).mapCone
                        { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                          π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.pt
hm :
  ∀ (j : K),
    m ≫
        {
                  liftedCone :=
                    { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                      π := NatTrans.mk fun t => { val := E.π.app t } },
                  validLift :=
                    Cones.ext
                      (eqToIso
                        (_ :
                          ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                            ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.π.app
          j =
      S.π.app j
⊢ m = (fun S => { val := IsLimit.lift hE ((sheafToPresheaf J D).mapCone S) }) S

Next tactic:
ext1
instance (F : K ⥤ Sheaf J D) : CreatesLimit F (sheafToPresheaf J D) :=
  createsLimitOfReflectsIso fun E hE =>
    { liftedCone := ⟨⟨E.pt, isSheaf_of_isLimit _ _ hE⟩,
        ⟨fun t => ⟨E.π.app _⟩, fun u v e => Sheaf.Hom.ext _ _ <| E.π.naturality _⟩⟩
      validLift := Cones.ext (eqToIso rfl) fun j => by
        dsimp
        simp
      makesLimit :=
        { lift := fun S => ⟨hE.lift ((sheafToPresheaf J D).mapCone S)⟩
          fac := fun S j => by
            ext1
            apply hE.fac ((sheafToPresheaf J D).mapCone S) j
          uniq := fun S m hm => by
            ext1
            

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝² : Category.{max v u, w} D
K : Type z
inst✝¹ : Category.{z', z} K
inst✝ : HasLimitsOfShape K D
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
hE : IsLimit E
S : Cone F
m :
  S.pt ⟶
    {
          liftedCone :=
            { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
              π := NatTrans.mk fun t => { val := E.π.app t } },
          validLift :=
            Cones.ext
              (eqToIso
                (_ :
                  ((sheafToPresheaf J D).mapCone
                        { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                          π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                    ((sheafToPresheaf J D).mapCone
                        { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                          π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.pt
hm :
  ∀ (j : K),
    m ≫
        {
                  liftedCone :=
                    { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                      π := NatTrans.mk fun t => { val := E.π.app t } },
                  validLift :=
                    Cones.ext
                      (eqToIso
                        (_ :
                          ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt =
                            ((sheafToPresheaf J D).mapCone
                                { pt := { val := E.pt, cond := (_ : Presheaf.IsSheaf J E.pt) },
                                  π := NatTrans.mk fun t => { val := E.π.app t } }).pt)) }.liftedCone.π.app
          j =
      S.π.app j
⊢ m.val = ((fun S => { val := IsLimit.lift hE ((sheafToPresheaf J D).mapCone S) }) S).val

Next tactic:
exact hE.uniq ((sheafToPresheaf J D).mapCone S) m.val fun j =>
              congr_arg Hom.val (hm j)
/-- Construct a cocone by sheafifying a cocone point of a cocone `E` of presheaves
over a functor which factors through sheaves.
In `isColimitSheafifyCocone`, we show that this is a colimit cocone when `E` is a colimit. -/
@[simps]
noncomputable def sheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) : Cocone F where
  pt := ⟨J.sheafify E.pt, GrothendieckTopology.Plus.isSheaf_plus_plus _ _⟩
  ι :=
    { app := fun k => ⟨E.ι.app k ≫ J.toSheafify E.pt⟩
      naturality := fun i j f => by
        

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
i j : K
f : i ⟶ j
⊢ F.map f ≫ (fun k => { val := E.ι.app k ≫ GrothendieckTopology.toSheafify J E.pt }) j =
    (fun k => { val := E.ι.app k ≫ GrothendieckTopology.toSheafify J E.pt }) i ≫
      ((Functor.const K).obj
            { val := GrothendieckTopology.sheafify J E.pt,
              cond :=
                (_ : Presheaf.IsSheaf J (GrothendieckTopology.plusObj J (GrothendieckTopology.plusObj J E.pt))) }).map
        f

Next tactic:
ext1
/-- Construct a cocone by sheafifying a cocone point of a cocone `E` of presheaves
over a functor which factors through sheaves.
In `isColimitSheafifyCocone`, we show that this is a colimit cocone when `E` is a colimit. -/
@[simps]
noncomputable def sheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) : Cocone F where
  pt := ⟨J.sheafify E.pt, GrothendieckTopology.Plus.isSheaf_plus_plus _ _⟩
  ι :=
    { app := fun k => ⟨E.ι.app k ≫ J.toSheafify E.pt⟩
      naturality := fun i j f => by
        ext1
        

Proof state:
case h
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
i j : K
f : i ⟶ j
⊢ (F.map f ≫ (fun k => { val := E.ι.app k ≫ GrothendieckTopology.toSheafify J E.pt }) j).val =
    ((fun k => { val := E.ι.app k ≫ GrothendieckTopology.toSheafify J E.pt }) i ≫
        ((Functor.const K).obj
              { val := GrothendieckTopology.sheafify J E.pt,
                cond :=
                  (_ : Presheaf.IsSheaf J (GrothendieckTopology.plusObj J (GrothendieckTopology.plusObj J E.pt))) }).map
          f).val

Next tactic:
dsimp
/-- Construct a cocone by sheafifying a cocone point of a cocone `E` of presheaves
over a functor which factors through sheaves.
In `isColimitSheafifyCocone`, we show that this is a colimit cocone when `E` is a colimit. -/
@[simps]
noncomputable def sheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) : Cocone F where
  pt := ⟨J.sheafify E.pt, GrothendieckTopology.Plus.isSheaf_plus_plus _ _⟩
  ι :=
    { app := fun k => ⟨E.ι.app k ≫ J.toSheafify E.pt⟩
      naturality := fun i j f => by
        ext1
        dsimp
        

Proof state:
case h
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
i j : K
f : i ⟶ j
⊢ (F.map f).val ≫ E.ι.app j ≫ GrothendieckTopology.toSheafify J E.pt =
    (E.ι.app i ≫ GrothendieckTopology.toSheafify J E.pt) ≫ 𝟙 (GrothendieckTopology.sheafify J E.pt)

Next tactic:
erw [Category.comp_id, ← Category.assoc, E.w f]
/-- If `E` is a colimit cocone of presheaves, over a diagram factoring through sheaves,
then `sheafifyCocone E` is a colimit cocone. -/
@[simps]
noncomputable def isColimitSheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) (hE : IsColimit E) : IsColimit (sheafifyCocone E) where
  desc S := ⟨J.sheafifyLift (hE.desc ((sheafToPresheaf J D).mapCocone S)) S.pt.2⟩
  fac := by
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
hE : IsColimit E
⊢ ∀ (s : Cocone F) (j : K),
    (sheafifyCocone E).ι.app j ≫
        (fun S =>
            {
              val :=
                GrothendieckTopology.sheafifyLift J (IsColimit.desc hE ((sheafToPresheaf J D).mapCocone S))
                  (_ : Presheaf.IsSheaf J S.pt.val) })
          s =
      s.ι.app j

Next tactic:
intro S j
/-- If `E` is a colimit cocone of presheaves, over a diagram factoring through sheaves,
then `sheafifyCocone E` is a colimit cocone. -/
@[simps]
noncomputable def isColimitSheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) (hE : IsColimit E) : IsColimit (sheafifyCocone E) where
  desc S := ⟨J.sheafifyLift (hE.desc ((sheafToPresheaf J D).mapCocone S)) S.pt.2⟩
  fac := by
    intro S j
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
hE : IsColimit E
S : Cocone F
j : K
⊢ (sheafifyCocone E).ι.app j ≫
      (fun S =>
          {
            val :=
              GrothendieckTopology.sheafifyLift J (IsColimit.desc hE ((sheafToPresheaf J D).mapCocone S))
                (_ : Presheaf.IsSheaf J S.pt.val) })
        S =
    S.ι.app j

Next tactic:
ext1
/-- If `E` is a colimit cocone of presheaves, over a diagram factoring through sheaves,
then `sheafifyCocone E` is a colimit cocone. -/
@[simps]
noncomputable def isColimitSheafifyCocone {F : K ⥤ Sheaf J D}
    (E : Cocone (F ⋙ sheafToPresheaf J D)) (hE : IsColimit E) : IsColimit (sheafifyCocone E) where
  desc S := ⟨J.sheafifyLift (hE.desc ((sheafToPresheaf J D).mapCocone S)) S.pt.2⟩
  fac := by
    intro S j
    ext1
    

Proof state:
case h
C : Type u
inst✝⁸ : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝⁷ : Category.{max v u, w} D
K : Type z
inst✝⁶ : Category.{z', z} K
inst✝⁵ : ConcreteCategory D
inst✝⁴ :
  ∀ (P : Cᵒᵖ ⥤ D) (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
inst✝³ : PreservesLimits (forget D)
inst✝² : ∀ (X : C), HasColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ D
inst✝¹ : (X : C) → PreservesColimitsOfShape (GrothendieckTopology.Cover J X)ᵒᵖ (forget D)
inst✝ : ReflectsIsomorphisms (forget D)
F : K ⥤ Sheaf J D
E : Cocone (F ⋙ sheafToPresheaf J D)
hE : IsColimit E
S : Cocone F
j : K
⊢ ((sheafifyCocone E).ι.app j ≫
        (fun S =>
            {
              val :=
                GrothendieckTopology.sheafifyLift J (IsColimit.desc hE ((sheafToPresheaf J D).mapCocone S))
                  (_ : Presheaf.IsSheaf J S.pt.val) })
          S).val =
    (S.ι.app j).val

Next tactic:
dsimp [sheafifyCocone]