l3lab/ntp-mathlib huggingface dataset:
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · 

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
⊢ IsSheaf (Pretopology.toGrothendieck C K) P → ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R

Next tactic:
intro PJ X R hR
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PJ : IsSheaf (Pretopology.toGrothendieck C K) P
X : C
R : Presieve X
hR : R ∈ Pretopology.coverings K X
⊢ IsSheafFor P R

Next tactic:
rw [isSheafFor_iff_generate]
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PJ : IsSheaf (Pretopology.toGrothendieck C K) P
X : C
R : Presieve X
hR : R ∈ Pretopology.coverings K X
⊢ IsSheafFor P (generate R).arrows

Next tactic:
apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · 

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
⊢ (∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R) → IsSheaf (Pretopology.toGrothendieck C K) P

Next tactic:
rintro PK X S ⟨R, hR, RS⟩
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    

Proof state:
case mpr.intro.intro
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
⊢ IsSheafFor P S.arrows

Next tactic:
have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      rwa [sets_iff_generate]
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
⊢ (generate R).arrows ≤ S.arrows

Next tactic:
apply giGenerate.gc.monotone_u
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      

Proof state:
case a
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
⊢ generate R ≤ S

Next tactic:
rwa [sets_iff_generate]
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      rwa [sets_iff_generate]
    

Proof state:
case mpr.intro.intro
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
gRS : (generate R).arrows ≤ S.arrows
⊢ IsSheafFor P S.arrows

Next tactic:
apply isSheafFor_subsieve P gRS _
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      rwa [sets_iff_generate]
    apply isSheafFor_subsieve P gRS _
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
gRS : (generate R).arrows ≤ S.arrows
⊢ ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSheafFor P (Sieve.pullback f (generate R)).arrows

Next tactic:
intro Y f
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      rwa [sets_iff_generate]
    apply isSheafFor_subsieve P gRS _
    intro Y f
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
gRS : (generate R).arrows ≤ S.arrows
Y : C
f : Y ⟶ X
⊢ IsSheafFor P (Sieve.pullback f (generate R)).arrows

Next tactic:
rw [← pullbackArrows_comm, ← isSheafFor_iff_generate]
/-- For a topology generated by a basis, it suffices to check the sheaf condition on the basis
presieves only.
-/
theorem isSheaf_pretopology [HasPullbacks C] (K : Pretopology C) :
    IsSheaf (K.toGrothendieck C) P ↔ ∀ {X : C} (R : Presieve X), R ∈ K X → IsSheafFor P R := by
  constructor
  · intro PJ X R hR
    rw [isSheafFor_iff_generate]
    apply PJ (Sieve.generate R) ⟨_, hR, le_generate R⟩
  · rintro PK X S ⟨R, hR, RS⟩
    have gRS : ⇑(generate R) ≤ S := by
      apply giGenerate.gc.monotone_u
      rwa [sets_iff_generate]
    apply isSheafFor_subsieve P gRS _
    intro Y f
    rw [← pullbackArrows_comm, ← isSheafFor_iff_generate]
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
inst✝ : HasPullbacks C
K : Pretopology C
PK : ∀ {X : C}, ∀ R ∈ Pretopology.coverings K X, IsSheafFor P R
X : C
S : Sieve X
R : Presieve X
hR : R ∈ Pretopology.coverings K X
RS : R ≤ S.arrows
gRS : (generate R).arrows ≤ S.arrows
Y : C
f : Y ⟶ X
⊢ IsSheafFor P (pullbackArrows f R)

Next tactic:
exact PK (pullbackArrows f R) (K.pullbacks f R hR)
/-- Any presheaf is a sheaf for the bottom (trivial) grothendieck topology. -/
theorem isSheaf_bot : IsSheaf (⊥ : GrothendieckTopology C) P := fun X => by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X✝ : C
J J₂ : GrothendieckTopology C
X : C
⊢ ∀ S ∈ GrothendieckTopology.sieves ⊥ X, IsSheafFor P S.arrows

Next tactic:
simp [isSheafFor_top_sieve]
/--
For a presheaf of the form `yoneda.obj W`, a compatible family of elements on a sieve
is the same as a co-cone over the sieve. Constructing a co-cone from a compatible family works for
any presieve, as does constructing a family of elements from a co-cone. Showing compatibility of the
family needs the sieve condition.
Note: This is related to `CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily`
 -/

def compatibleYonedaFamily_toCocone (R : Presieve X) (W : C) (x : FamilyOfElements (yoneda.obj W) R)
    (hx : FamilyOfElements.Compatible x) :
    Cocone (R.diagram) where
  pt := W
  ι :=
    { app := fun f => x f.obj.hom f.property
      naturality := by
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
R : Presieve X
W : C
x : FamilyOfElements (yoneda.obj W) R
hx : FamilyOfElements.Compatible x
⊢ ∀ ⦃X_1 Y : FullSubcategory fun f => R f.hom⦄ (f : X_1 ⟶ Y),
    (diagram R).map f ≫ (fun f => x f.obj.hom (_ : R f.obj.hom)) Y =
      (fun f => x f.obj.hom (_ : R f.obj.hom)) X_1 ≫ ((Functor.const (FullSubcategory fun f => R f.hom)).obj W).map f

Next tactic:
intro g₁ g₂ F
/--
For a presheaf of the form `yoneda.obj W`, a compatible family of elements on a sieve
is the same as a co-cone over the sieve. Constructing a co-cone from a compatible family works for
any presieve, as does constructing a family of elements from a co-cone. Showing compatibility of the
family needs the sieve condition.
Note: This is related to `CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily`
 -/

def compatibleYonedaFamily_toCocone (R : Presieve X) (W : C) (x : FamilyOfElements (yoneda.obj W) R)
    (hx : FamilyOfElements.Compatible x) :
    Cocone (R.diagram) where
  pt := W
  ι :=
    { app := fun f => x f.obj.hom f.property
      naturality := by
        intro g₁ g₂ F
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
R : Presieve X
W : C
x : FamilyOfElements (yoneda.obj W) R
hx : FamilyOfElements.Compatible x
g₁ g₂ : FullSubcategory fun f => R f.hom
F : g₁ ⟶ g₂
⊢ (diagram R).map F ≫ (fun f => x f.obj.hom (_ : R f.obj.hom)) g₂ =
    (fun f => x f.obj.hom (_ : R f.obj.hom)) g₁ ≫ ((Functor.const (FullSubcategory fun f => R f.hom)).obj W).map F

Next tactic:
simp only [Functor.id_obj, Functor.comp_obj, fullSubcategoryInclusion.obj, Over.forget_obj,
          Functor.const_obj_obj, Functor.comp_map, fullSubcategoryInclusion.map, Over.forget_map,
          Functor.const_obj_map, Category.comp_id]
/--
For a presheaf of the form `yoneda.obj W`, a compatible family of elements on a sieve
is the same as a co-cone over the sieve. Constructing a co-cone from a compatible family works for
any presieve, as does constructing a family of elements from a co-cone. Showing compatibility of the
family needs the sieve condition.
Note: This is related to `CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily`
 -/

def compatibleYonedaFamily_toCocone (R : Presieve X) (W : C) (x : FamilyOfElements (yoneda.obj W) R)
    (hx : FamilyOfElements.Compatible x) :
    Cocone (R.diagram) where
  pt := W
  ι :=
    { app := fun f => x f.obj.hom f.property
      naturality := by
        intro g₁ g₂ F
        simp only [Functor.id_obj, Functor.comp_obj, fullSubcategoryInclusion.obj, Over.forget_obj,
          Functor.const_obj_obj, Functor.comp_map, fullSubcategoryInclusion.map, Over.forget_map,
          Functor.const_obj_map, Category.comp_id]
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
R : Presieve X
W : C
x : FamilyOfElements (yoneda.obj W) R
hx : FamilyOfElements.Compatible x
g₁ g₂ : FullSubcategory fun f => R f.hom
F : g₁ ⟶ g₂
⊢ F.left ≫ x g₂.obj.hom (_ : R g₂.obj.hom) = x g₁.obj.hom (_ : R g₁.obj.hom)

Next tactic:
rw [← Category.id_comp (x g₁.obj.hom g₁.property)]
/--
For a presheaf of the form `yoneda.obj W`, a compatible family of elements on a sieve
is the same as a co-cone over the sieve. Constructing a co-cone from a compatible family works for
any presieve, as does constructing a family of elements from a co-cone. Showing compatibility of the
family needs the sieve condition.
Note: This is related to `CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily`
 -/

def compatibleYonedaFamily_toCocone (R : Presieve X) (W : C) (x : FamilyOfElements (yoneda.obj W) R)
    (hx : FamilyOfElements.Compatible x) :
    Cocone (R.diagram) where
  pt := W
  ι :=
    { app := fun f => x f.obj.hom f.property
      naturality := by
        intro g₁ g₂ F
        simp only [Functor.id_obj, Functor.comp_obj, fullSubcategoryInclusion.obj, Over.forget_obj,
          Functor.const_obj_obj, Functor.comp_map, fullSubcategoryInclusion.map, Over.forget_map,
          Functor.const_obj_map, Category.comp_id]
        rw [← Category.id_comp (x g₁.obj.hom g₁.property)]
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
R : Presieve X
W : C
x : FamilyOfElements (yoneda.obj W) R
hx : FamilyOfElements.Compatible x
g₁ g₂ : FullSubcategory fun f => R f.hom
F : g₁ ⟶ g₂
⊢ F.left ≫ x g₂.obj.hom (_ : R g₂.obj.hom) = 𝟙 (op ((𝟭 C).obj g₁.obj.left)).unop ≫ x g₁.obj.hom (_ : R g₁.obj.hom)

Next tactic:
apply hx
/--
For a presheaf of the form `yoneda.obj W`, a compatible family of elements on a sieve
is the same as a co-cone over the sieve. Constructing a co-cone from a compatible family works for
any presieve, as does constructing a family of elements from a co-cone. Showing compatibility of the
family needs the sieve condition.
Note: This is related to `CategoryTheory.Presheaf.conesEquivSieveCompatibleFamily`
 -/

def compatibleYonedaFamily_toCocone (R : Presieve X) (W : C) (x : FamilyOfElements (yoneda.obj W) R)
    (hx : FamilyOfElements.Compatible x) :
    Cocone (R.diagram) where
  pt := W
  ι :=
    { app := fun f => x f.obj.hom f.property
      naturality := by
        intro g₁ g₂ F
        simp only [Functor.id_obj, Functor.comp_obj, fullSubcategoryInclusion.obj, Over.forget_obj,
          Functor.const_obj_obj, Functor.comp_map, fullSubcategoryInclusion.map, Over.forget_map,
          Functor.const_obj_map, Category.comp_id]
        rw [← Category.id_comp (x g₁.obj.hom g₁.property)]
        apply hx
        

Proof state:
case a
C : Type u
inst✝ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type w
X : C
J J₂ : GrothendieckTopology C
R : Presieve X
W : C
x : FamilyOfElements (yoneda.obj W) R
hx : FamilyOfElements.Compatible x
g₁ g₂ : FullSubcategory fun f => R f.hom
F : g₁ ⟶ g₂
⊢ F.1 ≫ g₂.obj.hom = 𝟙 (op ((𝟭 C).obj g₁.obj.left)).unop ≫ g₁.obj.hom

Next tactic:
simp only [Functor.id_obj, Over.w, Opposite.unop_op, Category.id_comp]
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
⊢ FamilyOfElements.Compatible (yonedaFamilyOfElements_fromCocone S.arrows s)

Next tactic:
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ (yoneda.obj s.pt).map g₁.op (yonedaFamilyOfElements_fromCocone S.arrows s f₁ hf₁) =
    (yoneda.obj s.pt).map g₂.op (yonedaFamilyOfElements_fromCocone S.arrows s f₂ hf₂)

Next tactic:
have Hs := s.ι.naturality
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
⊢ (yoneda.obj s.pt).map g₁.op (yonedaFamilyOfElements_fromCocone S.arrows s f₁ hf₁) =
    (yoneda.obj s.pt).map g₂.op (yonedaFamilyOfElements_fromCocone S.arrows s f₂ hf₂)

Next tactic:
simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
⊢ g₁ ≫ yonedaFamilyOfElements_fromCocone S.arrows s f₁ hf₁ = g₂ ≫ yonedaFamilyOfElements_fromCocone S.arrows s f₂ hf₂

Next tactic:
dsimp [yonedaFamilyOfElements_fromCocone]
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
  dsimp [yonedaFamilyOfElements_fromCocone]
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
⊢ g₁ ≫ s.ι.app { obj := Over.mk f₁, property := hf₁ } = g₂ ≫ s.ι.app { obj := Over.mk f₂, property := hf₂ }

Next tactic:
have hgf₁ : S.arrows (g₁ ≫ f₁) := by exact Sieve.downward_closed S hf₁ g₁
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
  dsimp [yonedaFamilyOfElements_fromCocone]
  have hgf₁ : S.arrows (g₁ ≫ f₁) := by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
⊢ S.arrows (g₁ ≫ f₁)

Next tactic:
exact Sieve.downward_closed S hf₁ g₁
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
  dsimp [yonedaFamilyOfElements_fromCocone]
  have hgf₁ : S.arrows (g₁ ≫ f₁) := by exact Sieve.downward_closed S hf₁ g₁
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
hgf₁ : S.arrows (g₁ ≫ f₁)
⊢ g₁ ≫ s.ι.app { obj := Over.mk f₁, property := hf₁ } = g₂ ≫ s.ι.app { obj := Over.mk f₂, property := hf₂ }

Next tactic:
have hgf₂ : S.arrows (g₂ ≫ f₂) := by exact Sieve.downward_closed S hf₂ g₂
theorem yonedaFamily_fromCocone_compatible (S : Sieve X) (s : Cocone (diagram S.arrows)) :
    FamilyOfElements.Compatible <| yonedaFamilyOfElements_fromCocone S.arrows s := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ hgf
  have Hs := s.ι.naturality
  simp only [Functor.id_obj, yoneda_obj_obj, Opposite.unop_op, yoneda_obj_map, Quiver.Hom.unop_op]
  dsimp [yonedaFamilyOfElements_fromCocone]
  have hgf₁ : S.arrows (g₁ ≫ f₁) := by exact Sieve.downward_closed S hf₁ g₁
  have hgf₂ : S.arrows (g₂ ≫ f₂) := by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
X : C
S : Sieve X
s : Cocone (diagram S.arrows)
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
hgf : g₁ ≫ f₁ = g₂ ≫ f₂
Hs :
  ∀ ⦃X_1 Y : FullSubcategory fun f => S.arrows f.hom⦄ (f : X_1 ⟶ Y),
    (diagram S.arrows).map f ≫ s.ι.app Y =
      s.ι.app X_1 ≫ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)).obj s.pt).map f
hgf₁ : S.arrows (g₁ ≫ f₁)
⊢ S.arrows (g₂ ≫ f₂)

Next tactic:
exact Sieve.downward_closed S hf₂ g₂