Theorem: CategoryTheory.presheafHom_isSheafFor
File: Mathlib/CategoryTheory/Sites/SheafHom.lean

tactic: intro x hx
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
⊢ Presieve.IsSheafFor (presheafHom F G) S.arrows
state_after: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∃! t, x.IsAmalgamation t

tactic: apply exists_unique_of_exists_of_unique
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∃! t, x.IsAmalgamation t
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∃ x_1, x.IsAmalgamation x_1

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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∀ (y₁ y₂ : (presheafHom F G).obj { unop := X }), x.IsAmalgamation y₁ → x.IsAmalgamation y₂ → y₁ = y₂

tactic: 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 }, ?_⟩
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∃ x_1, x.IsAmalgamation x_1
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ x.IsAmalgamation { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }

tactic: rw [PresheafHom.isAmalgamation_iff _ _ hx]
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ x.IsAmalgamation { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g),
    { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }.app { unop := Over.mk g } =
      (x g hg).app { unop := Over.mk (𝟙 Y) }

tactic: intro Y g hg
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g),
    { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }.app { unop := Over.mk g } =
      (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }.app { unop := Over.mk g } =
    (x g hg).app { unop := Over.mk (𝟙 Y) }

tactic: dsimp
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ { app := fun Y => app hG x hx Y.unop.hom, naturality := ⋯ }.app { unop := Over.mk g } =
    (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }

tactic: have H := app_cond hG x hx g (𝟙 _) (by simpa using hg)
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g ≫ G.map (𝟙 Y).op = F.map (𝟙 Y).op ≫ (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }

tactic: rw [op_id, G.map_id, comp_id, F.map_id, id_comp] at H
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g ≫ G.map (𝟙 Y).op = F.map (𝟙 Y).op ≫ (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g = (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }

tactic: exact H.trans (by congr; simp)
state_before: case hex
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g = (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ app hG x hx g = (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: no goals

tactic: rintro ⟨Y₁ : Over X⟩ ⟨Y₂ : Over X⟩ ⟨φ : Y₂ ⟶ Y₁⟩
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∀ ⦃X_1 Y : (Over { unop := X }.unop)ᵒᵖ⦄ (f : X_1 ⟶ Y),
    ((Over.forget { unop := X }.unop).op ⋙ F).map f ≫ (fun Y => app hG x hx Y.unop.hom) Y =
      (fun Y => app hG x hx Y.unop.hom) X_1 ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map f
state_after: case op.op.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
⊢ ((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ } =
    (fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }

tactic: apply (hG Y₂.hom).hom_ext
state_before: case op.op.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
⊢ ((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ } =
    (fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }
state_after: case op.op.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
⊢ ∀ (j : (Sieve.pullback Y₂.hom S).arrows.categoryᵒᵖ),
    (((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ }) ≫
        (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app j =
      ((fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }) ≫
        (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app j

tactic: rintro ⟨Z : Over Y₂.left, hZ⟩
state_before: case op.op.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
⊢ ∀ (j : (Sieve.pullback Y₂.hom S).arrows.categoryᵒᵖ),
    (((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ }) ≫
        (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app j =
      ((fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }) ≫
        (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app j
state_after: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ (((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ }) ≫
      (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } } =
    ((fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }) ≫
      (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } }

tactic: dsimp
state_before: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ (((Over.forget { unop := X }.unop).op ⋙ F).map { unop := φ } ≫ (fun Y => app hG x hx Y.unop.hom) { unop := Y₂ }) ≫
      (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } } =
    ((fun Y => app hG x hx Y.unop.hom) { unop := Y₁ } ≫ ((Over.forget { unop := X }.unop).op ⋙ G).map { unop := φ }) ≫
      (G.mapCone (Sieve.pullback Y₂.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } }
state_after: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ (F.map φ.left.op ≫ app hG x hx Y₂.hom) ≫ G.map Z.hom.op = (app hG x hx Y₁.hom ≫ G.map φ.left.op) ≫ G.map Z.hom.op

tactic: rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp]
state_before: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ (F.map φ.left.op ≫ app hG x hx Y₂.hom) ≫ G.map Z.hom.op = (app hG x hx Y₁.hom ≫ G.map φ.left.op) ≫ G.map Z.hom.op
state_after: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ F.map φ.left.op ≫ F.map Z.hom.op ≫ (x (Z.hom ≫ Y₂.hom) hZ).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) } =
    app hG x hx Y₁.hom ≫ G.map (Z.hom ≫ φ.left).op

tactic: erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ),
  ← F.map_comp_assoc, op_comp]
state_before: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ F.map φ.left.op ≫ F.map Z.hom.op ≫ (x (Z.hom ≫ Y₂.hom) hZ).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) } =
    app hG x hx Y₁.hom ≫ G.map (Z.hom ≫ φ.left).op
state_after: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ F.map (φ.left.op ≫ Z.hom.op) ≫ (x (Z.hom ≫ Y₂.hom) hZ).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) } =
    F.map (φ.left.op ≫ Z.hom.op) ≫ (x ((Z.hom ≫ φ.left) ≫ Y₁.hom) ⋯).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) }

tactic: congr 3
state_before: case op.op.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ F.map (φ.left.op ≫ Z.hom.op) ≫ (x (Z.hom ≫ Y₂.hom) hZ).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) } =
    F.map (φ.left.op ≫ Z.hom.op) ≫ (x ((Z.hom ≫ φ.left) ≫ Y₁.hom) ⋯).app { unop := Over.mk (𝟙 ((𝟭 C).obj Z.left)) }
state_after: case op.op.op.op.mk.e_a.e_self.e_f
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ Z.hom ≫ Y₂.hom = (Z.hom ≫ φ.left) ≫ Y₁.hom

tactic: simp
state_before: case op.op.op.op.mk.e_a.e_self.e_f
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ Z.hom ≫ Y₂.hom = (Z.hom ≫ φ.left) ≫ Y₁.hom
state_after: no goals

tactic: simpa using hZ
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y₁ Y₂ : Over X
φ : Y₂ ⟶ Y₁
Z : Over Y₂.left
hZ : (Sieve.pullback Y₂.hom S).arrows Z.hom
⊢ S.arrows ((Z.hom ≫ φ.left) ≫ Y₁.hom)
state_after: no goals

tactic: simpa using hg
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ S.arrows (𝟙 Y ≫ g)
state_after: no goals

tactic: congr
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g = (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) } = (x g hg).app { unop := Over.mk (𝟙 Y) }
state_after: case e_self.e_f
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g = (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ 𝟙 Y ≫ g = g

tactic: simp
state_before: case e_self.e_f
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
Y : C
g : Y ⟶ X
hg : S.arrows g
H : app hG x hx g = (x (𝟙 Y ≫ g) ⋯).app { unop := Over.mk (𝟙 Y) }
⊢ 𝟙 Y ≫ g = g
state_after: no goals

tactic: intro y₁ y₂ hy₁ hy₂
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
⊢ ∀ (y₁ y₂ : (presheafHom F G).obj { unop := X }), x.IsAmalgamation y₁ → x.IsAmalgamation y₂ → y₁ = y₂
state_after: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : x.IsAmalgamation y₁
hy₂ : x.IsAmalgamation y₂
⊢ y₁ = y₂

tactic: rw [PresheafHom.isAmalgamation_iff _ _ hx] at hy₁ hy₂
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : x.IsAmalgamation y₁
hy₂ : x.IsAmalgamation y₂
⊢ y₁ = y₂
state_after: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
⊢ y₁ = y₂

tactic: apply NatTrans.ext
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
⊢ y₁ = y₂
state_after: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
⊢ y₁.app = y₂.app

tactic: ext ⟨Y : Over X⟩
state_before: 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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
⊢ y₁.app = y₂.app
state_after: case hunique.app.h.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
Y : Over X
⊢ y₁.app { unop := Y } = y₂.app { unop := Y }

tactic: apply (hG Y.hom).hom_ext
state_before: case hunique.app.h.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
Y : Over X
⊢ y₁.app { unop := Y } = y₂.app { unop := Y }
state_after: case hunique.app.h.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
Y : Over X
⊢ ∀ (j : (Sieve.pullback Y.hom S).arrows.categoryᵒᵖ),
    y₁.app { unop := Y } ≫ (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app j =
      y₂.app { unop := Y } ≫ (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app j

tactic: rintro ⟨Z : Over Y.left, hZ⟩
state_before: case hunique.app.h.op
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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
Y : Over X
⊢ ∀ (j : (Sieve.pullback Y.hom S).arrows.categoryᵒᵖ),
    y₁.app { unop := Y } ≫ (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app j =
      y₂.app { unop := Y } ≫ (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app j
state_after: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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 (Sieve.pullback Y.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } } =
    y₂.app { unop := Y } ≫
      (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } }

tactic: dsimp
state_before: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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 (Sieve.pullback Y.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } } =
    y₂.app { unop := Y } ≫
      (G.mapCone (Sieve.pullback Y.hom S).arrows.cocone.op).π.app { unop := { obj := Z, property := hZ } }
state_after: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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

tactic: let φ : Over.mk (Z.hom ≫ Y.hom) ⟶ Y := Over.homMk Z.hom
state_before: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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
state_after: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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

tactic: refine (y₁.naturality φ.op).symm.trans (Eq.trans ?_ (y₂.naturality φ.op))
state_before: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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
state_after: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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 { unop := X }.unop).op ⋙ F).map φ.op ≫ y₁.app { unop := Over.mk (Z.hom ≫ Y.hom) } =
    ((Over.forget { unop := X }.unop).op ⋙ F).map φ.op ≫ y₂.app { unop := Over.mk (Z.hom ≫ Y.hom) }

tactic: rw [(hy₁ _ _ hZ), ← ((hy₂ _ _ hZ))]
state_before: case hunique.app.h.op.op.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 (Sieve.pullback f S).arrows.cocone.op)
x : Presieve.FamilyOfElements (presheafHom F G) S.arrows
hx : x.Compatible
y₁ y₂ : (presheafHom F G).obj { unop := X }
hy₁ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₁.app { unop := Over.mk g } = (x g hg).app { unop := Over.mk (𝟙 Y) }
hy₂ : ∀ (Y : C) (g : Y ⟶ X) (hg : S.arrows g), y₂.app { unop := Over.mk g } = (x g hg).app { unop := 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 { unop := X }.unop).op ⋙ F).map φ.op ≫ y₁.app { unop := Over.mk (Z.hom ≫ Y.hom) } =
    ((Over.forget { unop := X }.unop).op ⋙ F).map φ.op ≫ y₂.app { unop := Over.mk (Z.hom ≫ Y.hom) }
state_after: no goals