l3lab/ntp-mathlib huggingface dataset:
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    

Proof state:
case hunique
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : Presieve.FamilyOfElements.IsAmalgamation x y₁
hy₂ : Presieve.FamilyOfElements.IsAmalgamation x y₂
⊢ y₁ = y₂

Next tactic:
rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    

Proof state:
case hunique
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
⊢ y₁ = y₂

Next tactic:
apply NatTrans.ext
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    

Proof state:
case hunique.app
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
⊢ y₁.app = y₂.app

Next tactic:
ext ⟨Y : Over X⟩
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    

Proof state:
case hunique.app.h.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
⊢ y₁.app { unop := Y } = y₂.app { unop := Y }

Next tactic:
apply (hG Y.hom).hom_ext
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    apply (hG Y.hom).hom_ext
    

Proof state:
case hunique.app.h.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
⊢ ∀ (j : (FullSubcategory fun f => (Sieve.pullback Y.hom S).arrows f.hom)ᵒᵖ),
    y₁.app { unop := Y } ≫ (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback Y.hom S).arrows))).π.app j =
      y₂.app { unop := Y } ≫ (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback Y.hom S).arrows))).π.app j

Next tactic:
rintro ⟨Z : Over Y.left, hZ⟩
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    apply (hG Y.hom).hom_ext
    rintro ⟨Z : Over Y.left, hZ⟩
    

Proof state:
case hunique.app.h.mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
Z : Over Y.left
hZ : (Sieve.pullback Y.hom S).arrows Z.hom
⊢ y₁.app { unop := Y } ≫
      (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback Y.hom S).arrows))).π.app
        { unop := { obj := Z, property := hZ } } =
    y₂.app { unop := Y } ≫
      (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback Y.hom S).arrows))).π.app
        { unop := { obj := Z, property := hZ } }

Next tactic:
dsimp
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    apply (hG Y.hom).hom_ext
    rintro ⟨Z : Over Y.left, hZ⟩
    dsimp
    

Proof state:
case hunique.app.h.mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
Z : Over Y.left
hZ : (Sieve.pullback Y.hom S).arrows Z.hom
⊢ y₁.app { unop := Y } ≫ G.map Z.hom.op = y₂.app { unop := Y } ≫ G.map Z.hom.op

Next tactic:
let φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    apply (hG Y.hom).hom_ext
    rintro ⟨Z : Over Y.left, hZ⟩
    dsimp
    let φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
    

Proof state:
case hunique.app.h.mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
Z : Over Y.left
hZ : (Sieve.pullback Y.hom S).arrows Z.hom
φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
⊢ y₁.app { unop := Y } ≫ G.map Z.hom.op = y₂.app { unop := Y } ≫ G.map Z.hom.op

Next tactic:
refine' (y₁.naturality φ.op).symm.trans (Eq.trans _ (y₂.naturality φ.op))
open PresheafHom.IsSheafFor in
lemma presheafHom_isSheafFor  :
    Presieve.IsSheafFor (presheafHom F G) S.arrows := by
  intro x hx
  apply exists_unique_of_exists_of_unique
  · refine' ⟨
      { app := fun Y => app hG x hx Y.unop.hom
        naturality := by
          rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
          apply (hG Y₂.hom).hom_ext
          rintro ⟨Z : Over Y₂.left, hZ⟩
          dsimp
          rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
          erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
            ← F.map_comp_assoc, op_comp]
          congr 3
          simp }, _⟩
    rw [PresheafHom.isAmalgamation_iff _ _ hx]
    intro Y g hg
    dsimp
    have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
    rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
    exact H.trans (by congr; simp)
  · intro y₁ y₂ hy₁ hy₂
    rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
    apply NatTrans.ext
    ext ⟨Y : Over X⟩
    apply (hG Y.hom).hom_ext
    rintro ⟨Z : Over Y.left, hZ⟩
    dsimp
    let φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
    refine' (y₁.naturality φ.op).symm.trans (Eq.trans _ (y₂.naturality φ.op))
    

Proof state:
case hunique.app.h.mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
S : Sieve X
hG : ⦃Y : C⦄ → (f : Y ⟶ X) → IsLimit (G.mapCone (Cocone.op (Presieve.cocone (Sieve.pullback f S).arrows)))
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
y₁ y₂ : (presheafHom F G).obj (op X)
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app (op (Over.mk g)) = (x g hg).app (op (Over.mk (𝟙 Y)))
Y : Over X
Z : Over Y.left
hZ : (Sieve.pullback Y.hom S).arrows Z.hom
φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
⊢ ((Over.forget (op X).unop).op ⋙ F).map φ.op ≫ y₁.app (op (Over.mk (Z.hom ≫ Y.hom))) =
    ((Over.forget (op X).unop).op ⋙ F).map φ.op ≫ y₂.app (op (Over.mk (Z.hom ≫ Y.hom)))

Next tactic:
rw [(hy₁ _ _ hZ), ← ((hy₂ _ _ hZ))]
lemma Presheaf.IsSheaf.hom (hG : Presheaf.IsSheaf J G) :
    Presheaf.IsSheaf J (presheafHom F G) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
hG : IsSheaf J G
⊢ IsSheaf J (presheafHom F G)

Next tactic:
rw [isSheaf_iff_isSheaf_of_type]
lemma Presheaf.IsSheaf.hom (hG : Presheaf.IsSheaf J G) :
    Presheaf.IsSheaf J (presheafHom F G) := by
  rw [isSheaf_iff_isSheaf_of_type]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
hG : IsSheaf J G
⊢ Presieve.IsSheaf J (presheafHom F G)

Next tactic:
intro X S hS
lemma Presheaf.IsSheaf.hom (hG : Presheaf.IsSheaf J G) :
    Presheaf.IsSheaf J (presheafHom F G) := by
  rw [isSheaf_iff_isSheaf_of_type]
  intro X S hS
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
hG : IsSheaf J G
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
⊢ Presieve.IsSheafFor (presheafHom F G) S.arrows

Next tactic:
exact presheafHom_isSheafFor F G S
    (fun _ _ => ((Presheaf.isSheaf_iff_isLimit J G).1 hG _ (J.pullback_stable _ hS)).some)
/-- The underlying presheaf of `sheafHom F G`. It is isomorphic to `presheafHom F.1 G.1`
(see `sheafHom'Iso`), but has better definitional properties. -/
def sheafHom' (F G : Sheaf J A) : Cᵒᵖ ⥤ Type _ where
  obj X := (J.overPullback A X.unop).obj F ⟶ (J.overPullback A X.unop).obj G
  map f := fun φ => (J.overMapPullback A f.unop).map φ
  map_id X := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F✝ G✝ : Cᵒᵖ ⥤ A
F G : Sheaf J A
X : Cᵒᵖ
⊢ {
          obj := fun X =>
            (GrothendieckTopology.overPullback J A X.unop).obj F ⟶ (GrothendieckTopology.overPullback J A X.unop).obj G,
          map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
      (𝟙 X) =
    𝟙
      ({
            obj := fun X =>
              (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                (GrothendieckTopology.overPullback J A X.unop).obj G,
            map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.obj
        X)

Next tactic:
ext φ : 2
/-- The underlying presheaf of `sheafHom F G`. It is isomorphic to `presheafHom F.1 G.1`
(see `sheafHom'Iso`), but has better definitional properties. -/
def sheafHom' (F G : Sheaf J A) : Cᵒᵖ ⥤ Type _ where
  obj X := (J.overPullback A X.unop).obj F ⟶ (J.overPullback A X.unop).obj G
  map f := fun φ => (J.overMapPullback A f.unop).map φ
  map_id X := by
    ext φ : 2
    

Proof state:
case h.h
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F✝ G✝ : Cᵒᵖ ⥤ A
F G : Sheaf J A
X : Cᵒᵖ
φ :
  {
        obj := fun X =>
          (GrothendieckTopology.overPullback J A X.unop).obj F ⟶ (GrothendieckTopology.overPullback J A X.unop).obj G,
        map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.obj
    X
⊢ ({
            obj := fun X =>
              (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                (GrothendieckTopology.overPullback J A X.unop).obj G,
            map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
        (𝟙 X) φ).val =
    (𝟙
        ({
              obj := fun X =>
                (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                  (GrothendieckTopology.overPullback J A X.unop).obj G,
              map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.obj
          X)
        φ).val

Next tactic:
exact congr_fun ((presheafHom F.1 G.1).map_id X) φ.1
/-- The underlying presheaf of `sheafHom F G`. It is isomorphic to `presheafHom F.1 G.1`
(see `sheafHom'Iso`), but has better definitional properties. -/
def sheafHom' (F G : Sheaf J A) : Cᵒᵖ ⥤ Type _ where
  obj X := (J.overPullback A X.unop).obj F ⟶ (J.overPullback A X.unop).obj G
  map f := fun φ => (J.overMapPullback A f.unop).map φ
  map_id X := by
    ext φ : 2
    exact congr_fun ((presheafHom F.1 G.1).map_id X) φ.1
  map_comp f g := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F✝ G✝ : Cᵒᵖ ⥤ A
F G : Sheaf J A
X✝ Y✝ Z✝ : Cᵒᵖ
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
⊢ {
          obj := fun X =>
            (GrothendieckTopology.overPullback J A X.unop).obj F ⟶ (GrothendieckTopology.overPullback J A X.unop).obj G,
          map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
      (f ≫ g) =
    {
            obj := fun X =>
              (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                (GrothendieckTopology.overPullback J A X.unop).obj G,
            map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
        f ≫
      {
            obj := fun X =>
              (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                (GrothendieckTopology.overPullback J A X.unop).obj G,
            map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
        g

Next tactic:
ext φ : 2
/-- The underlying presheaf of `sheafHom F G`. It is isomorphic to `presheafHom F.1 G.1`
(see `sheafHom'Iso`), but has better definitional properties. -/
def sheafHom' (F G : Sheaf J A) : Cᵒᵖ ⥤ Type _ where
  obj X := (J.overPullback A X.unop).obj F ⟶ (J.overPullback A X.unop).obj G
  map f := fun φ => (J.overMapPullback A f.unop).map φ
  map_id X := by
    ext φ : 2
    exact congr_fun ((presheafHom F.1 G.1).map_id X) φ.1
  map_comp f g := by
    ext φ : 2
    

Proof state:
case h.h
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F✝ G✝ : Cᵒᵖ ⥤ A
F G : Sheaf J A
X✝ Y✝ Z✝ : Cᵒᵖ
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
φ :
  {
        obj := fun X =>
          (GrothendieckTopology.overPullback J A X.unop).obj F ⟶ (GrothendieckTopology.overPullback J A X.unop).obj G,
        map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.obj
    X✝
⊢ ({
            obj := fun X =>
              (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                (GrothendieckTopology.overPullback J A X.unop).obj G,
            map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
        (f ≫ g) φ).val =
    (({
                obj := fun X =>
                  (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                    (GrothendieckTopology.overPullback J A X.unop).obj G,
                map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
            f ≫
          {
                obj := fun X =>
                  (GrothendieckTopology.overPullback J A X.unop).obj F ⟶
                    (GrothendieckTopology.overPullback J A X.unop).obj G,
                map := fun {X Y} f φ => (GrothendieckTopology.overMapPullback J A f.unop).map φ }.map
            g)
        φ).val

Next tactic:
exact congr_fun ((presheafHom F.1 G.1).map_comp f g) φ.1
@[simp]
/- Porting note: abomination -/
theorem id_hom (X : C) : Iso.hom (coreCategory.id X) = @CategoryStruct.id C _ X := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
X : C
⊢ (𝟙 X).hom = 𝟙 X

Next tactic:
rfl