[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X✝ : C
S : Sieve X✝
R : Presieve X✝
E : Aᵒᵖ
π : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj E
X Y : C
f : X ⟶ X✝
g : Y ⟶ X
hf : S.arrows f
⊢ (fun Y f h => NatTrans.app π (op { obj := Over.mk f, property := h })) Y (g ≫ f) (_ : S.arrows (g ≫ f)) =
    (P ⋙ coyoneda.obj E).map g.op ((fun Y f h => NatTrans.app π (op { obj := Over.mk f, property := h })) X f hf)
[PROOFSTEP]
apply (id_comp _).symm.trans
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X✝ : C
S : Sieve X✝
R : Presieve X✝
E : Aᵒᵖ
π : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj E
X Y : C
f : X ⟶ X✝
g : Y ⟶ X
hf : S.arrows f
⊢ 𝟙
        (((Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).op.obj E).unop.obj
          (op { obj := Over.mk (g ≫ f), property := (_ : S.arrows (g ≫ f)) })) ≫
      (fun Y f h => NatTrans.app π (op { obj := Over.mk f, property := h })) Y (g ≫ f) (_ : S.arrows (g ≫ f)) =
    (P ⋙ coyoneda.obj E).map g.op ((fun Y f h => NatTrans.app π (op { obj := Over.mk f, property := h })) X f hf)
[PROOFSTEP]
dsimp
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X✝ : C
S : Sieve X✝
R : Presieve X✝
E : Aᵒᵖ
π : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj E
X Y : C
f : X ⟶ X✝
g : Y ⟶ X
hf : S.arrows f
⊢ 𝟙 E.unop ≫ NatTrans.app π (op { obj := Over.mk (g ≫ f), property := (_ : S.arrows (g ≫ f)) }) =
    NatTrans.app π (op { obj := Over.mk f, property := hf }) ≫ P.map g.op
[PROOFSTEP]
exact π.naturality (Quiver.Hom.op (Over.homMk _ (by rfl)))
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X✝ : C
S : Sieve X✝
R : Presieve X✝
E : Aᵒᵖ
π : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj E
X Y : C
f : X ⟶ X✝
g : Y ⟶ X
hf : S.arrows f
⊢ g ≫ { obj := Over.mk f, property := hf }.obj.hom =
    { obj := Over.mk (g ≫ f), property := (_ : S.arrows (g ≫ f)) }.obj.hom
[PROOFSTEP]
rfl
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : { x // SieveCompatible x }
f f' : (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ
g : f ⟶ f'
⊢ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).op.obj E).unop.map g ≫
      (fun f => ↑x f.unop.obj.hom (_ : S.arrows f.unop.obj.hom)) f' =
    (fun f => ↑x f.unop.obj.hom (_ : S.arrows f.unop.obj.hom)) f ≫ ((diagram S.arrows).op ⋙ P).map g
[PROOFSTEP]
refine' Eq.trans _ (x.2 f.unop.1.hom g.unop.left f.unop.2)
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : { x // SieveCompatible x }
f f' : (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ
g : f ⟶ f'
⊢ ((Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).op.obj E).unop.map g ≫
      (fun f => ↑x f.unop.obj.hom (_ : S.arrows f.unop.obj.hom)) f' =
    ↑x (g.unop.left ≫ f.unop.obj.hom) (_ : S.arrows (g.unop.left ≫ f.unop.obj.hom))
[PROOFSTEP]
dsimp
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : { x // SieveCompatible x }
f f' : (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ
g : f ⟶ f'
⊢ 𝟙 E.unop ≫ ↑x f'.unop.obj.hom (_ : S.arrows f'.unop.obj.hom) =
    ↑x (g.unop.left ≫ f.unop.obj.hom) (_ : S.arrows (g.unop.left ≫ f.unop.obj.hom))
[PROOFSTEP]
rw [id_comp]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : { x // SieveCompatible x }
f f' : (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ
g : f ⟶ f'
⊢ ↑x f'.unop.obj.hom (_ : S.arrows f'.unop.obj.hom) =
    ↑x (g.unop.left ≫ f.unop.obj.hom) (_ : S.arrows (g.unop.left ≫ f.unop.obj.hom))
[PROOFSTEP]
convert rfl
[GOAL]
case h.e'_3.h.e'_4
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : { x // SieveCompatible x }
f f' : (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ
g : f ⟶ f'
⊢ g.unop.left ≫ f.unop.obj.hom = f'.unop.obj.hom
[PROOFSTEP]
rw [Over.w]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ Nonempty (IsLimit (P.mapCone (Cocone.op (cocone S.arrows)))) ↔ ∀ (E : Aᵒᵖ), IsSheafFor (P ⋙ coyoneda.obj E) S.arrows
[PROOFSTEP]
dsimp [IsSheafFor]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ Nonempty (IsLimit (P.mapCone (Cocone.op (cocone S.arrows)))) ↔
    ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), Compatible x → ∃! t, IsAmalgamation x t
[PROOFSTEP]
simp_rw [compatible_iff_sieveCompatible]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ Nonempty (IsLimit (P.mapCone (Cocone.op (cocone S.arrows)))) ↔
    ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
[PROOFSTEP]
rw [((Cone.isLimitEquivIsTerminal _).trans (isTerminalEquivUnique _ _)).nonempty_congr]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ Nonempty ((X_1 : Cone ((diagram S.arrows).op ⋙ P)) → Unique (X_1 ⟶ P.mapCone (Cocone.op (cocone S.arrows)))) ↔
    ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
[PROOFSTEP]
rw [Classical.nonempty_pi]
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (i : Cone ((diagram S.arrows).op ⋙ P)), Nonempty (Unique (i ⟶ P.mapCone (Cocone.op (cocone S.arrows))))) ↔
    ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (i : Cone ((diagram S.arrows).op ⋙ P)), Nonempty (Unique (i ⟶ P.mapCone (Cocone.op (cocone S.arrows))))) →
    ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
[PROOFSTEP]
intro hu E x hx
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
hu : ∀ (i : Cone ((diagram S.arrows).op ⋙ P)), Nonempty (Unique (i ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ ∃! t, IsAmalgamation x t
[PROOFSTEP]
specialize hu hx.cone
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
hu : Nonempty (Unique (SieveCompatible.cone hx ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
⊢ ∃! t, IsAmalgamation x t
[PROOFSTEP]
erw [(homEquivAmalgamation hx).uniqueCongr.nonempty_congr] at hu 
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
hu : Nonempty (Unique { t // IsAmalgamation x t })
⊢ ∃! t, IsAmalgamation x t
[PROOFSTEP]
exact (unique_subtype_iff_exists_unique _).1 hu
[GOAL]
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t) →
    ∀ (i : Cone ((diagram S.arrows).op ⋙ P)), Nonempty (Unique (i ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
[PROOFSTEP]
rintro h ⟨E, π⟩
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
⊢ Nonempty (Unique ({ pt := E, π := π } ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
[PROOFSTEP]
let eqv := conesEquivSieveCompatibleFamily P S (op E)
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ Nonempty (Unique ({ pt := E, π := π } ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
[PROOFSTEP]
rw [← eqv.left_inv π]
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ Nonempty (Unique ({ pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))))
[PROOFSTEP]
erw [(homEquivAmalgamation (eqv π).2).uniqueCongr.nonempty_congr]
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ Nonempty (Unique { t // IsAmalgamation (↑(↑eqv π)) t })
[PROOFSTEP]
rw [unique_subtype_iff_exists_unique]
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ) (x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows), SieveCompatible x → ∃! t, IsAmalgamation x t
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ ∃! a, IsAmalgamation (↑(↑eqv π)) a
[PROOFSTEP]
exact h _ _ (eqv π).2
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))) ↔
    ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))) →
    ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
[PROOFSTEP]
intro hs E x t₁ t₂ h₁ h₂
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x✝
hs : ∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
t₁ t₂ : (P ⋙ coyoneda.obj E).obj (op X)
h₁ : IsAmalgamation x t₁
h₂ : IsAmalgamation x t₂
⊢ t₁ = t₂
[PROOFSTEP]
have hx := is_compatible_of_exists_amalgamation x ⟨t₁, h₁⟩
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
hs : ∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
t₁ t₂ : (P ⋙ coyoneda.obj E).obj (op X)
h₁ : IsAmalgamation x t₁
h₂ : IsAmalgamation x t₂
hx : Compatible x
⊢ t₁ = t₂
[PROOFSTEP]
rw [compatible_iff_sieveCompatible] at hx 
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
hs : ∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
t₁ t₂ : (P ⋙ coyoneda.obj E).obj (op X)
h₁ : IsAmalgamation x t₁
h₂ : IsAmalgamation x t₂
hx : SieveCompatible x
⊢ t₁ = t₂
[PROOFSTEP]
specialize hs hx.cone
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
t₁ t₂ : (P ⋙ coyoneda.obj E).obj (op X)
h₁ : IsAmalgamation x t₁
h₂ : IsAmalgamation x t₂
hx : SieveCompatible x
hs : Subsingleton (SieveCompatible.cone hx ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
⊢ t₁ = t₂
[PROOFSTEP]
rcases hs with ⟨hs⟩
[GOAL]
case mp.intro
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x✝ : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx✝ : SieveCompatible x✝
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
t₁ t₂ : (P ⋙ coyoneda.obj E).obj (op X)
h₁ : IsAmalgamation x t₁
h₂ : IsAmalgamation x t₂
hx : SieveCompatible x
hs : ∀ (a b : SieveCompatible.cone hx ⟶ P.mapCone (Cocone.op (cocone S.arrows))), a = b
⊢ t₁ = t₂
[PROOFSTEP]
simpa only [Subtype.mk.injEq] using
  (show Subtype.mk t₁ h₁ = ⟨t₂, h₂⟩ from (homEquivAmalgamation hx).symm.injective (hs _ _))
[GOAL]
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
⊢ (∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows) →
    ∀ (c : Cone ((diagram S.arrows).op ⋙ P)), Subsingleton (c ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
[PROOFSTEP]
rintro h ⟨E, π⟩
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
⊢ Subsingleton ({ pt := E, π := π } ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
[PROOFSTEP]
let eqv := conesEquivSieveCompatibleFamily P S (op E)
[GOAL]
case mpr.mk
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ Subsingleton ({ pt := E, π := π } ⟶ P.mapCone (Cocone.op (cocone S.arrows)))
[PROOFSTEP]
constructor
[GOAL]
case mpr.mk.allEq
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ ∀ (a b : { pt := E, π := π } ⟶ P.mapCone (Cocone.op (cocone S.arrows))), a = b
[PROOFSTEP]
rw [← eqv.left_inv π]
[GOAL]
case mpr.mk.allEq
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
⊢ ∀ (a b : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))), a = b
[PROOFSTEP]
intro f₁ f₂
[GOAL]
case mpr.mk.allEq
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
⊢ f₁ = f₂
[PROOFSTEP]
let eqv' := homEquivAmalgamation (eqv π).2
[GOAL]
case mpr.mk.allEq
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
eqv' : (SieveCompatible.cone (_ : SieveCompatible ↑(↑eqv π)) ⟶ P.mapCone (Cocone.op (cocone S.arrows))) ≃
  { t // IsAmalgamation (↑(↑eqv π)) t } :=
  homEquivAmalgamation (_ : SieveCompatible ↑(↑eqv π))
⊢ f₁ = f₂
[PROOFSTEP]
apply eqv'.injective
[GOAL]
case mpr.mk.allEq.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
eqv' : (SieveCompatible.cone (_ : SieveCompatible ↑(↑eqv π)) ⟶ P.mapCone (Cocone.op (cocone S.arrows))) ≃
  { t // IsAmalgamation (↑(↑eqv π)) t } :=
  homEquivAmalgamation (_ : SieveCompatible ↑(↑eqv π))
⊢ ↑eqv' f₁ = ↑eqv' f₂
[PROOFSTEP]
ext
[GOAL]
case mpr.mk.allEq.a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
eqv' : (SieveCompatible.cone (_ : SieveCompatible ↑(↑eqv π)) ⟶ P.mapCone (Cocone.op (cocone S.arrows))) ≃
  { t // IsAmalgamation (↑(↑eqv π)) t } :=
  homEquivAmalgamation (_ : SieveCompatible ↑(↑eqv π))
⊢ ↑(↑eqv' f₁) = ↑(↑eqv' f₂)
[PROOFSTEP]
apply h _ (eqv π).1
[GOAL]
case mpr.mk.allEq.a.a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
eqv' : (SieveCompatible.cone (_ : SieveCompatible ↑(↑eqv π)) ⟶ P.mapCone (Cocone.op (cocone S.arrows))) ≃
  { t // IsAmalgamation (↑(↑eqv π)) t } :=
  homEquivAmalgamation (_ : SieveCompatible ↑(↑eqv π))
⊢ IsAmalgamation ↑(↑eqv π) ↑(↑eqv' f₁)
[PROOFSTEP]
exact (eqv' _).2
[GOAL]
case mpr.mk.allEq.a.a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E✝ : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E✝) S.arrows
hx : SieveCompatible x
h : ∀ (E : Aᵒᵖ), IsSeparatedFor (P ⋙ coyoneda.obj E) S.arrows
E : A
π : (Functor.const (FullSubcategory fun f => S.arrows f.hom)ᵒᵖ).obj E ⟶ (diagram S.arrows).op ⋙ P
eqv : (Functor.cones ((diagram S.arrows).op ⋙ P)).obj (op E) ≃ { x // SieveCompatible x } :=
  conesEquivSieveCompatibleFamily P S (op E)
f₁ f₂ : { pt := E, π := Equiv.invFun eqv (Equiv.toFun eqv π) } ⟶ P.mapCone (Cocone.op (cocone S.arrows))
eqv' : (SieveCompatible.cone (_ : SieveCompatible ↑(↑eqv π)) ⟶ P.mapCone (Cocone.op (cocone S.arrows))) ≃
  { t // IsAmalgamation (↑(↑eqv π)) t } :=
  homEquivAmalgamation (_ : SieveCompatible ↑(↑eqv π))
⊢ IsAmalgamation ↑(↑eqv π) ↑(↑eqv' f₂)
[PROOFSTEP]
exact (eqv' _).2
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
inst✝ : HasPullbacks C
K : Pretopology C
⊢ IsSheaf (Pretopology.toGrothendieck C K) P ↔
    ∀ ⦃X : C⦄ (R : Presieve X),
      R ∈ Pretopology.coverings K X → Nonempty (IsLimit (P.mapCone (Cocone.op (cocone (generate R).arrows))))
[PROOFSTEP]
dsimp [IsSheaf]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
inst✝ : HasPullbacks C
K : Pretopology C
⊢ (∀ (E : A), Presieve.IsSheaf (Pretopology.toGrothendieck C K) (P ⋙ coyoneda.obj (op E))) ↔
    ∀ ⦃X : C⦄ (R : Presieve X),
      R ∈ Pretopology.coverings K X → Nonempty (IsLimit (P.mapCone (Cocone.op (cocone (generate R).arrows))))
[PROOFSTEP]
simp_rw [isSheaf_pretopology]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
J : GrothendieckTopology C
P : Cᵒᵖ ⥤ A
X : C
S : Sieve X
R : Presieve X
E : Aᵒᵖ
x : FamilyOfElements (P ⋙ coyoneda.obj E) S.arrows
hx : SieveCompatible x
inst✝ : HasPullbacks C
K : Pretopology C
⊢ (∀ (E : A) {X : C} (R : Presieve X), R ∈ Pretopology.coverings K X → IsSheafFor (P ⋙ coyoneda.obj (op E)) R) ↔
    ∀ ⦃X : C⦄ (R : Presieve X),
      R ∈ Pretopology.coverings K X → Nonempty (IsLimit (P.mapCone (Cocone.op (cocone (generate R).arrows))))
[PROOFSTEP]
exact
  ⟨fun h X R hR => (isLimit_iff_isSheafFor_presieve P R).2 fun E => h E.unop R hR, fun h E X R hR =>
    (isLimit_iff_isSheafFor_presieve P R).1 (h R hR) (op E)⟩
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A✝ : Type u₂
inst✝¹ : Category.{v₂, u₂} A✝
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
E : A
X : C
P : Cᵒᵖ ⥤ A
hP : IsSheaf J P
S : GrothendieckTopology.Cover J X
x : (I : GrothendieckTopology.Cover.Arrow S) → E ⟶ P.obj (op I.Y)
hx :
  ∀ (I : GrothendieckTopology.Cover.Relation S),
    x (GrothendieckTopology.Cover.Relation.fst I) ≫ P.map I.g₁.op =
      x (GrothendieckTopology.Cover.Relation.snd I) ≫ P.map I.g₂.op
I : GrothendieckTopology.Cover.Arrow S
⊢ amalgamate hP S x hx ≫ P.map I.f.op = x I
[PROOFSTEP]
rcases I with ⟨Y, f, hf⟩
[GOAL]
case mk
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A✝ : Type u₂
inst✝¹ : Category.{v₂, u₂} A✝
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
E : A
X : C
P : Cᵒᵖ ⥤ A
hP : IsSheaf J P
S : GrothendieckTopology.Cover J X
x : (I : GrothendieckTopology.Cover.Arrow S) → E ⟶ P.obj (op I.Y)
hx :
  ∀ (I : GrothendieckTopology.Cover.Relation S),
    x (GrothendieckTopology.Cover.Relation.fst I) ≫ P.map I.g₁.op =
      x (GrothendieckTopology.Cover.Relation.snd I) ≫ P.map I.g₂.op
Y : C
f : Y ⟶ X
hf : (GrothendieckTopology.Cover.sieve S).arrows f
⊢ amalgamate hP S x hx ≫ P.map { Y := Y, f := f, hf := hf }.f.op = x { Y := Y, f := f, hf := hf }
[PROOFSTEP]
apply
  @Presieve.IsSheafFor.valid_glue _ _ _ _ _ _ (hP _ _ S.condition) (fun Y f hf => x ⟨Y, f, hf⟩)
    (fun Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ w => hx ⟨Y₁, Y₂, Z, g₁, g₂, f₁, f₂, h₁, h₂, w⟩) f hf
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
⊢ Presheaf.IsSheaf J P ↔ Presieve.IsSheaf J P
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
⊢ Presheaf.IsSheaf J P → Presieve.IsSheaf J P
[PROOFSTEP]
intro hP
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presheaf.IsSheaf J P
⊢ Presieve.IsSheaf J P
[PROOFSTEP]
refine' Presieve.isSheaf_iso J _ (hP PUnit)
[GOAL]
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presheaf.IsSheaf J P
⊢ P ⋙ coyoneda.obj (op PUnit) ≅ P
[PROOFSTEP]
refine' isoWhiskerLeft _ Coyoneda.punitIso ≪≫ P.rightUnitor
[GOAL]
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
⊢ Presieve.IsSheaf J P → Presheaf.IsSheaf J P
[PROOFSTEP]
intro hP X Y S hS z hz
[GOAL]
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation z t
[PROOFSTEP]
refine' ⟨fun x => (hP S hS).amalgamate (fun Z f hf => z f hf x) _, _, _⟩
[GOAL]
case mpr.refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
x : (op X).unop
⊢ Presieve.FamilyOfElements.Compatible fun Z f hf => z f hf x
[PROOFSTEP]
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ h
[GOAL]
case mpr.refine'_1
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
x : (op X).unop
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ Y
f₂ : Y₂ ⟶ Y
hf₁ : S.arrows f₁
hf₂ : S.arrows f₂
h : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ P.map g₁.op ((fun Z f hf => z f hf x) Y₁ f₁ hf₁) = P.map g₂.op ((fun Z f hf => z f hf x) Y₂ f₂ hf₂)
[PROOFSTEP]
exact congr_fun (hz g₁ g₂ hf₁ hf₂ h) x
[GOAL]
case mpr.refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
⊢ (fun t => Presieve.FamilyOfElements.IsAmalgamation z t) fun x =>
    Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
      (_ :
        ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁) (hf₂ : S.arrows f₂),
          g₁ ≫ f₁ = g₂ ≫ f₂ →
            (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x)
[PROOFSTEP]
intro Z f hf
[GOAL]
case mpr.refine'_2
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
Z : C
f : Z ⟶ Y
hf : S.arrows f
⊢ ((P ⋙ coyoneda.obj (op X)).map f.op fun x =>
      Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
        (_ :
          ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁)
            (hf₂ : S.arrows f₂),
            g₁ ≫ f₁ = g₂ ≫ f₂ →
              (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x)) =
    z f hf
[PROOFSTEP]
funext x
[GOAL]
case mpr.refine'_2.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
Z : C
f : Z ⟶ Y
hf : S.arrows f
x : (op X).unop
⊢ (P ⋙ coyoneda.obj (op X)).map f.op
      (fun x =>
        Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
          (_ :
            ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁)
              (hf₂ : S.arrows f₂),
              g₁ ≫ f₁ = g₂ ≫ f₂ →
                (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x))
      x =
    z f hf x
[PROOFSTEP]
apply Presieve.IsSheafFor.valid_glue
[GOAL]
case mpr.refine'_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
⊢ ∀ (y : (P ⋙ coyoneda.obj (op X)).obj (op Y)),
    (fun t => Presieve.FamilyOfElements.IsAmalgamation z t) y →
      y = fun x =>
        Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
          (_ :
            ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁)
              (hf₂ : S.arrows f₂),
              g₁ ≫ f₁ = g₂ ≫ f₂ →
                (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x)
[PROOFSTEP]
intro y hy
[GOAL]
case mpr.refine'_3
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
y : (P ⋙ coyoneda.obj (op X)).obj (op Y)
hy : Presieve.FamilyOfElements.IsAmalgamation z y
⊢ y = fun x =>
    Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
      (_ :
        ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁) (hf₂ : S.arrows f₂),
          g₁ ≫ f₁ = g₂ ≫ f₂ →
            (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x)
[PROOFSTEP]
funext x
[GOAL]
case mpr.refine'_3.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
y : (P ⋙ coyoneda.obj (op X)).obj (op Y)
hy : Presieve.FamilyOfElements.IsAmalgamation z y
x : (op X).unop
⊢ y x =
    Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
      (_ :
        ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁) (hf₂ : S.arrows f₂),
          g₁ ≫ f₁ = g₂ ≫ f₂ →
            (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x)
[PROOFSTEP]
apply (hP S hS).isSeparatedFor.ext
[GOAL]
case mpr.refine'_3.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
y : (P ⋙ coyoneda.obj (op X)).obj (op Y)
hy : Presieve.FamilyOfElements.IsAmalgamation z y
x : (op X).unop
⊢ ∀ ⦃Y_1 : C⦄ ⦃f : Y_1 ⟶ Y⦄,
    S.arrows f →
      P.map f.op (y x) =
        P.map f.op
          (Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
            (_ :
              ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁)
                (hf₂ : S.arrows f₂),
                g₁ ≫ f₁ = g₂ ≫ f₂ →
                  (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x))
[PROOFSTEP]
intro Y' f hf
[GOAL]
case mpr.refine'_3.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
y : (P ⋙ coyoneda.obj (op X)).obj (op Y)
hy : Presieve.FamilyOfElements.IsAmalgamation z y
x : (op X).unop
Y' : C
f : Y' ⟶ Y
hf : S.arrows f
⊢ P.map f.op (y x) =
    P.map f.op
      (Presieve.IsSheafFor.amalgamate (_ : Presieve.IsSheafFor P S.arrows) (fun Z f hf => z f hf x)
        (_ :
          ∀ ⦃Y₁ Y₂ Z : C⦄ (g₁ : Z ⟶ Y₁) (g₂ : Z ⟶ Y₂) ⦃f₁ : Y₁ ⟶ Y⦄ ⦃f₂ : Y₂ ⟶ Y⦄ (hf₁ : S.arrows f₁)
            (hf₂ : S.arrows f₂),
            g₁ ≫ f₁ = g₂ ≫ f₂ →
              (P ⋙ coyoneda.obj (op X)).map g₁.op (z f₁ hf₁) x = (P ⋙ coyoneda.obj (op X)).map g₂.op (z f₂ hf₂) x))
[PROOFSTEP]
rw [Presieve.IsSheafFor.valid_glue _ _ _ hf, ← hy _ hf]
[GOAL]
case mpr.refine'_3.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
P : Cᵒᵖ ⥤ Type w
hP : Presieve.IsSheaf J P
X : Type w
Y : C
S : Sieve Y
hS : S ∈ GrothendieckTopology.sieves J Y
z : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op X)) S.arrows
hz : Presieve.FamilyOfElements.Compatible z
y : (P ⋙ coyoneda.obj (op X)).obj (op Y)
hy : Presieve.FamilyOfElements.IsAmalgamation z y
x : (op X).unop
Y' : C
f : Y' ⟶ Y
hf : S.arrows f
⊢ P.map f.op (y x) = (P ⋙ coyoneda.obj (op X)).map f.op y x
[PROOFSTEP]
rfl
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
⊢ IsTerminal (F.val.obj (op X))
[PROOFSTEP]
refine' @IsTerminal.ofUnique _ _ _ ?_
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
⊢ (X_1 : A) → Unique (X_1 ⟶ F.val.obj (op X))
[PROOFSTEP]
intro Y
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
Y : A
⊢ Unique (Y ⟶ F.val.obj (op X))
[PROOFSTEP]
choose t h using F.2 Y _ H (by tauto) (by tauto)
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
Y : A
⊢ Presieve.FamilyOfElements (F.val ⋙ coyoneda.obj (op Y)) ⊥.arrows
[PROOFSTEP]
tauto
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
Y : A
⊢ Presieve.FamilyOfElements.Compatible
    (let_fun em := Classical.propDecidable;
    fun ⦃Y_1⦄ f a => False.elim (_ : False))
[PROOFSTEP]
tauto
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
Y : A
t : (F.val ⋙ coyoneda.obj (op Y)).obj (op X)
h :
  (fun t =>
        Presieve.FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y_1⦄ f a => False.elim (_ : False))
          t)
      t ∧
    ∀ (y : (F.val ⋙ coyoneda.obj (op Y)).obj (op X)),
      (fun t =>
            Presieve.FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y_1⦄ f a => False.elim (_ : False))
              t)
          y →
        y = t
⊢ Unique (Y ⟶ F.val.obj (op X))
[PROOFSTEP]
exact ⟨⟨t⟩, fun a => h.2 a (by tauto)⟩
[GOAL]
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝ : Category.{v₂, u₂} A
F : Sheaf J A
X : C
H : ⊥ ∈ GrothendieckTopology.sieves J X
Y : A
t : (F.val ⋙ coyoneda.obj (op Y)).obj (op X)
h :
  (fun t =>
        Presieve.FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y_1⦄ f a => False.elim (_ : False))
          t)
      t ∧
    ∀ (y : (F.val ⋙ coyoneda.obj (op Y)).obj (op X)),
      (fun t =>
            Presieve.FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y_1⦄ f a => False.elim (_ : False))
              t)
          y →
        y = t
a : Y ⟶ F.val.obj (op X)
⊢ (fun t =>
      Presieve.FamilyOfElements.IsAmalgamation
        (let_fun em := Classical.propDecidable;
        fun ⦃Y_1⦄ f a => False.elim (_ : False))
        t)
    a
[PROOFSTEP]
tauto
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
n : ℤ
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
⊢ P.val.map i ≫ (fun U => n • NatTrans.app f.val U) V = (fun U => n • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
induction' n using Int.induction_on with n ih n ih
[GOAL]
case hz
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
⊢ P.val.map i ≫ (fun U => 0 • NatTrans.app f.val U) V = (fun U => 0 • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
simp only [zero_smul, comp_zero, zero_comp]
[GOAL]
case hp
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
n : ℕ
ih : P.val.map i ≫ (fun U => ↑n • NatTrans.app f.val U) V = (fun U => ↑n • NatTrans.app f.val U) U ≫ Q.val.map i
⊢ P.val.map i ≫ (fun U => (↑n + 1) • NatTrans.app f.val U) V =
    (fun U => (↑n + 1) • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
simpa only [add_zsmul, one_zsmul, comp_add, NatTrans.naturality, add_comp, add_left_inj]
[GOAL]
case hn
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
n : ℕ
ih : P.val.map i ≫ (fun U => -↑n • NatTrans.app f.val U) V = (fun U => -↑n • NatTrans.app f.val U) U ≫ Q.val.map i
⊢ P.val.map i ≫ (fun U => (-↑n - 1) • NatTrans.app f.val U) V =
    (fun U => (-↑n - 1) • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
simpa only [sub_smul, one_zsmul, comp_sub, NatTrans.naturality, sub_comp, sub_left_inj] using ih
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
n : ℕ
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
⊢ P.val.map i ≫ (fun U => n • NatTrans.app f.val U) V = (fun U => n • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
induction' n with n ih
[GOAL]
case zero
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
⊢ P.val.map i ≫ (fun U => Nat.zero • NatTrans.app f.val U) V =
    (fun U => Nat.zero • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
simp only [zero_smul, comp_zero, zero_comp, Nat.zero_eq]
[GOAL]
case succ
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
f : P ⟶ Q
U V : Cᵒᵖ
i : U ⟶ V
n : ℕ
ih : P.val.map i ≫ (fun U => n • NatTrans.app f.val U) V = (fun U => n • NatTrans.app f.val U) U ≫ Q.val.map i
⊢ P.val.map i ≫ (fun U => Nat.succ n • NatTrans.app f.val U) V =
    (fun U => Nat.succ n • NatTrans.app f.val U) U ≫ Q.val.map i
[PROOFSTEP]
simp only [Nat.succ_eq_add_one, add_smul, ih, one_nsmul, comp_add, NatTrans.naturality, add_comp]
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
x✝¹ : P ⟶ Q
x✝ : ℕ
⊢ (fun f => f.val) (x✝ • x✝¹) = x✝ • (fun f => f.val) x✝¹
[PROOFSTEP]
aesop_cat
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : GrothendieckTopology C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
inst✝ : Preadditive A
P Q : Sheaf J A
x✝¹ : P ⟶ Q
x✝ : ℤ
⊢ (fun f => f.val) (x✝ • x✝¹) = x✝ • (fun f => f.val) x✝¹
[PROOFSTEP]
aesop_cat
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
⊢ ∀ (s : Cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)))
    (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    (fun E =>
            IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
              (_ :
                ∀ (I : GrothendieckTopology.Cover.Relation S),
                  Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                    Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
          s ≫
        NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j =
      NatTrans.app s.π j
[PROOFSTEP]
rintro (E : Multifork _) (a | b)
[GOAL]
case left
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
a : (GrothendieckTopology.Cover.index S P).L
⊢ (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork S P).π (WalkingMulticospan.left a) =
    NatTrans.app E.π (WalkingMulticospan.left a)
[PROOFSTEP]
apply hP.amalgamate_map
[GOAL]
case right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
b : (GrothendieckTopology.Cover.index S P).R
⊢ (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork S P).π (WalkingMulticospan.right b) =
    NatTrans.app E.π (WalkingMulticospan.right b)
[PROOFSTEP]
rw [← E.w (WalkingMulticospan.Hom.fst b), ← (S.multifork P).w (WalkingMulticospan.Hom.fst b), ← assoc]
[GOAL]
case right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
b : (GrothendieckTopology.Cover.index S P).R
⊢ ((fun E =>
            IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
              (_ :
                ∀ (I : GrothendieckTopology.Cover.Relation S),
                  Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                    Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
          E ≫
        NatTrans.app (GrothendieckTopology.Cover.multifork S P).π
          (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) b))) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)).map (WalkingMulticospan.Hom.fst b) =
    NatTrans.app E.π (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) b)) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)).map (WalkingMulticospan.Hom.fst b)
[PROOFSTEP]
congr 1
[GOAL]
case right.e_a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
b : (GrothendieckTopology.Cover.index S P).R
⊢ (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork S P).π
        (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) b)) =
    NatTrans.app E.π (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) b))
[PROOFSTEP]
apply hP.amalgamate_map
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
⊢ ∀ (s : Cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)))
    (m : s.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt),
    (∀
        (j :
          WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
        m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app s.π j) →
      m =
        (fun E =>
            IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
              (_ :
                ∀ (I : GrothendieckTopology.Cover.Relation S),
                  Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                    Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
          s
[PROOFSTEP]
rintro (E : Multifork _) m hm
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
m : E.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt
hm :
  ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app E.π j
⊢ m =
    (fun E =>
        IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
          (_ :
            ∀ (I : GrothendieckTopology.Cover.Relation S),
              Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                  MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                  MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
      E
[PROOFSTEP]
apply hP.hom_ext S
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
m : E.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt
hm :
  ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app E.π j
⊢ ∀ (I : GrothendieckTopology.Cover.Arrow S),
    m ≫ P.map I.f.op =
      (fun E =>
            IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
              (_ :
                ∀ (I : GrothendieckTopology.Cover.Relation S),
                  Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                    Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                      MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
          E ≫
        P.map I.f.op
[PROOFSTEP]
intro I
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
m : E.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt
hm :
  ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app E.π j
I : GrothendieckTopology.Cover.Arrow S
⊢ m ≫ P.map I.f.op =
    (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      P.map I.f.op
[PROOFSTEP]
erw [hm (WalkingMulticospan.left I)]
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
m : E.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt
hm :
  ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app E.π j
I : GrothendieckTopology.Cover.Arrow S
⊢ NatTrans.app E.π (WalkingMulticospan.left I) =
    (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      P.map I.f.op
[PROOFSTEP]
symm
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
X : C
S : GrothendieckTopology.Cover J X
hP : IsSheaf J P
E : Multifork (GrothendieckTopology.Cover.index S P)
m : E.pt ⟶ (GrothendieckTopology.Cover.multifork S P).pt
hm :
  ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    m ≫ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j = NatTrans.app E.π j
I : GrothendieckTopology.Cover.Arrow S
⊢ (fun E =>
          IsSheaf.amalgamate hP S (fun I => Multifork.ι E I)
            (_ :
              ∀ (I : GrothendieckTopology.Cover.Relation S),
                Multifork.ι E (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) I =
                  Multifork.ι E (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index S P) I) ≫
                    MulticospanIndex.snd (GrothendieckTopology.Cover.index S P) I))
        E ≫
      P.map I.f.op =
    NatTrans.app E.π (WalkingMulticospan.left I)
[PROOFSTEP]
apply hP.amalgamate_map
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
⊢ IsSheaf J P ↔
    ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
[PROOFSTEP]
refine' ⟨fun hP X S => ⟨isLimitOfIsSheaf _ _ _ hP⟩, _⟩
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
⊢ (∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))) →
    IsSheaf J P
[PROOFSTEP]
intro h E X S hS x hx
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t
[PROOFSTEP]
let T : J.Cover X := ⟨S, hS⟩
[GOAL]
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t
[PROOFSTEP]
obtain ⟨hh⟩ := h _ T
[GOAL]
case intro
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t
[PROOFSTEP]
let K : Multifork (T.index P) := Multifork.ofι _ E (fun I => x I.f I.hf) fun I => hx _ _ _ _ I.w
[GOAL]
case intro
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t
[PROOFSTEP]
use hh.lift K
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ (fun t => Presieve.FamilyOfElements.IsAmalgamation x t) (IsLimit.lift hh K) ∧
    ∀ (y : (P ⋙ coyoneda.obj (op E)).obj (op X)),
      (fun t => Presieve.FamilyOfElements.IsAmalgamation x t) y → y = IsLimit.lift hh K
[PROOFSTEP]
dsimp
[GOAL]
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ Presieve.FamilyOfElements.IsAmalgamation x
      (IsLimit.lift hh
        (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
          (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
          (_ :
            ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
              (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                  (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f)) =
                (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                  (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f))))) ∧
    ∀ (y : E ⟶ P.obj (op X)),
      Presieve.FamilyOfElements.IsAmalgamation x y →
        y =
          IsLimit.lift hh
            (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
              (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
              (_ :
                ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
                  (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                      (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                        (_ :
                          (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                            (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                                I).f)) =
                    (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                      (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                        (_ :
                          (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                            (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                                I).f))))
[PROOFSTEP]
constructor
[GOAL]
case h.left
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ Presieve.FamilyOfElements.IsAmalgamation x
    (IsLimit.lift hh
      (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
        (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
        (_ :
          ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
            (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f)) =
              (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                          I).f)))))
[PROOFSTEP]
intro Y f hf
[GOAL]
case h.left
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
Y : C
f : Y ⟶ X
hf : S.arrows f
⊢ (P ⋙ coyoneda.obj (op E)).map f.op
      (IsLimit.lift hh
        (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
          (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
          (_ :
            ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
              (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                  (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f)) =
                (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                  (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f))))) =
    x f hf
[PROOFSTEP]
apply hh.fac K (WalkingMulticospan.left ⟨Y, f, hf⟩)
[GOAL]
case h.right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ ∀ (y : E ⟶ P.obj (op X)),
    Presieve.FamilyOfElements.IsAmalgamation x y →
      y =
        IsLimit.lift hh
          (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
            (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
            (_ :
              ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
                (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                    (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                      (_ :
                        (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                          (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                              I).f)) =
                  (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                    (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                      (_ :
                        (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                          (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                              I).f))))
[PROOFSTEP]
intro e he
[GOAL]
case h.right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
⊢ e =
    IsLimit.lift hh
      (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
        (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
        (_ :
          ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
            (P ⋙ coyoneda.obj (op E)).map I.g₁.op
                (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f)) =
              (P ⋙ coyoneda.obj (op E)).map I.g₂.op
                (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f))))
[PROOFSTEP]
apply hh.uniq K
[GOAL]
case h.right.x
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
⊢ ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index T P).fstTo (GrothendieckTopology.Cover.index T P).sndTo),
    e ≫ NatTrans.app (GrothendieckTopology.Cover.multifork T P).π j = NatTrans.app K.π j
[PROOFSTEP]
rintro (a | b)
[GOAL]
case h.right.x.left
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
a : (GrothendieckTopology.Cover.index T P).L
⊢ e ≫ NatTrans.app (GrothendieckTopology.Cover.multifork T P).π (WalkingMulticospan.left a) =
    NatTrans.app K.π (WalkingMulticospan.left a)
[PROOFSTEP]
apply he
[GOAL]
case h.right.x.right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ e ≫ NatTrans.app (GrothendieckTopology.Cover.multifork T P).π (WalkingMulticospan.right b) =
    NatTrans.app K.π (WalkingMulticospan.right b)
[PROOFSTEP]
rw [← K.w (WalkingMulticospan.Hom.fst b), ← (T.multifork P).w (WalkingMulticospan.Hom.fst b), ← assoc]
[GOAL]
case h.right.x.right
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ (e ≫
        NatTrans.app (GrothendieckTopology.Cover.multifork T P).π
          (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b))) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index T P)).map (WalkingMulticospan.Hom.fst b) =
    NatTrans.app K.π (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b)) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index T P)).map (WalkingMulticospan.Hom.fst b)
[PROOFSTEP]
congr 1
[GOAL]
case h.right.x.right.e_a
C : Type u₁
inst✝² : Category.{v₁, u₁} C
A : Type u₂
inst✝¹ : Category.{v₂, u₂} A
A' : Type u₂
inst✝ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj (op E)) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj (op E)).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj (op E)).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj (op X)
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ e ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork T P).π
        (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b)) =
    NatTrans.app K.π (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b))
[PROOFSTEP]
apply he
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
⊢ IsSheaf J P ↔ ∀ (X : C) (S : GrothendieckTopology.Cover J X), IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
[PROOFSTEP]
rw [isSheaf_iff_multifork]
[GOAL]
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
⊢ (∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))) ↔
    ∀ (X : C) (S : GrothendieckTopology.Cover J X), IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
[PROOFSTEP]
refine' forall₂_congr fun X S => ⟨_, _⟩
[GOAL]
case refine'_1
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
⊢ Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P)) →
    IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
[PROOFSTEP]
rintro ⟨h⟩
[GOAL]
case refine'_1.intro
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsLimit (GrothendieckTopology.Cover.multifork S P)
⊢ IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
[PROOFSTEP]
let e : P.obj (op X) ≅ multiequalizer (S.index P) := h.conePointUniqueUpToIso (limit.isLimit _)
[GOAL]
case refine'_1.intro
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsLimit (GrothendieckTopology.Cover.multifork S P)
e : P.obj (op X) ≅ multiequalizer (GrothendieckTopology.Cover.index S P) :=
  IsLimit.conePointUniqueUpToIso h (limit.isLimit (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)))
⊢ IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
[PROOFSTEP]
exact (inferInstance : IsIso e.hom)
[GOAL]
case refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
⊢ IsIso (GrothendieckTopology.Cover.toMultiequalizer S P) →
    Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
[PROOFSTEP]
intro h
[GOAL]
case refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
⊢ Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
[PROOFSTEP]
refine' ⟨IsLimit.ofIsoLimit (limit.isLimit _) (Cones.ext _ _)⟩
[GOAL]
case refine'_2.refine'_1
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
⊢ (limit.cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P))).pt ≅
    (GrothendieckTopology.Cover.multifork S P).pt
[PROOFSTEP]
apply (@asIso _ _ _ _ _ h).symm
[GOAL]
case refine'_2.refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
⊢ ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo),
    NatTrans.app (limit.cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P))).π j =
      (asIso (GrothendieckTopology.Cover.toMultiequalizer S P)).symm.hom ≫
        NatTrans.app (GrothendieckTopology.Cover.multifork S P).π j
[PROOFSTEP]
intro a
[GOAL]
case refine'_2.refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
a : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo
⊢ NatTrans.app (limit.cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P))).π a =
    (asIso (GrothendieckTopology.Cover.toMultiequalizer S P)).symm.hom ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork S P).π a
[PROOFSTEP]
symm
[GOAL]
case refine'_2.refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
a : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo
⊢ (asIso (GrothendieckTopology.Cover.toMultiequalizer S P)).symm.hom ≫
      NatTrans.app (GrothendieckTopology.Cover.multifork S P).π a =
    NatTrans.app (limit.cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P))).π a
[PROOFSTEP]
erw [IsIso.inv_comp_eq]
[GOAL]
case refine'_2.refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
a : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo
⊢ NatTrans.app (GrothendieckTopology.Cover.multifork S P).π a =
    GrothendieckTopology.Cover.toMultiequalizer S P ≫
      NatTrans.app (limit.cone (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P))).π a
[PROOFSTEP]
dsimp
[GOAL]
case refine'_2.refine'_2
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
A : Type u₂
inst✝² : Category.{v₂, u₂} A
A' : Type u₂
inst✝¹ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝ : ∀ (X : C) (S : GrothendieckTopology.Cover J X), HasMultiequalizer (GrothendieckTopology.Cover.index S P)
X : C
S : GrothendieckTopology.Cover J X
h : IsIso (GrothendieckTopology.Cover.toMultiequalizer S P)
a : WalkingMulticospan (GrothendieckTopology.Cover.index S P).fstTo (GrothendieckTopology.Cover.index S P).sndTo
⊢ (match a with
    | WalkingMulticospan.left a => P.map a.f.op
    | WalkingMulticospan.right b =>
      P.map (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index S P) b).f.op ≫
        MulticospanIndex.fst (GrothendieckTopology.Cover.index S P) b) =
    GrothendieckTopology.Cover.toMultiequalizer S P ≫
      limit.π (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index S P)) a
[PROOFSTEP]
simp
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
⊢ forkMap R P ≫ firstMap R P = forkMap R P ≫ secondMap R P
[PROOFSTEP]
apply limit.hom_ext
[GOAL]
case w
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
⊢ ∀ (j : Discrete (((V : C) × { f // R f }) × (W : C) × { g // R g })),
    (forkMap R P ≫ firstMap R P) ≫
        limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j =
      (forkMap R P ≫ secondMap R P) ≫
        limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j
[PROOFSTEP]
rintro ⟨⟨Y, f, hf⟩, ⟨Z, g, hg⟩⟩
[GOAL]
case w.mk.mk.mk.mk.mk.mk
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
Y : C
f : Y ⟶ U
hf : R f
Z : C
g : Z ⟶ U
hg : R g
⊢ (forkMap R P ≫ firstMap R P) ≫
      limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))
        {
          as :=
            ({ fst := Y, snd := { val := f, property := hf } }, { fst := Z, snd := { val := g, property := hg } }) } =
    (forkMap R P ≫ secondMap R P) ≫
      limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))
        { as := ({ fst := Y, snd := { val := f, property := hf } }, { fst := Z, snd := { val := g, property := hg } }) }
[PROOFSTEP]
simp only [firstMap, secondMap, forkMap, limit.lift_π, limit.lift_π_assoc, assoc, Fan.mk_π_app, Subtype.coe_mk]
[GOAL]
case w.mk.mk.mk.mk.mk.mk
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
Y : C
f : Y ⟶ U
hf : R f
Z : C
g : Z ⟶ U
hg : R g
⊢ P.map f.op ≫ P.map pullback.fst.op = P.map g.op ≫ P.map pullback.snd.op
[PROOFSTEP]
rw [← P.map_comp, ← op_comp, pullback.condition]
[GOAL]
case w.mk.mk.mk.mk.mk.mk
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
Y : C
f : Y ⟶ U
hf : R f
Z : C
g : Z ⟶ U
hg : R g
⊢ P.map (pullback.snd ≫ g).op = P.map g.op ≫ P.map pullback.snd.op
[PROOFSTEP]
simp
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ IsLimit (s.mapCone (Fork.ofι (forkMap R P) (_ : forkMap R P ≫ firstMap R P = forkMap R P ≫ secondMap R P))) ≃
    IsLimit
      (Fork.ofι (Equalizer.forkMap (P ⋙ s) R)
        (_ :
          Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.firstMap (P ⋙ s) R =
            Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.secondMap (P ⋙ s) R))
[PROOFSTEP]
apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ IsLimit
      (Fork.ofι (s.map (forkMap R P))
        (_ : s.map (forkMap R P) ≫ s.map (firstMap R P) = s.map (forkMap R P) ≫ s.map (secondMap R P))) ≃
    IsLimit
      (Fork.ofι (Equalizer.forkMap (P ⋙ s) R)
        (_ :
          Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.firstMap (P ⋙ s) R =
            Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.secondMap (P ⋙ s) R))
[PROOFSTEP]
apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ parallelPair (s.map (firstMap R P)) (s.map (secondMap R P)) ≅
    parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)
[PROOFSTEP]
apply NatIso.ofComponents _ _
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (X : WalkingParallelPair) →
    (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).obj X ≅
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).obj X
[PROOFSTEP]
rintro (_ | _)
[GOAL]
case zero
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).obj WalkingParallelPair.zero ≅
    (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).obj
      WalkingParallelPair.zero
[PROOFSTEP]
apply PreservesProduct.iso s
[GOAL]
case one
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).obj WalkingParallelPair.one ≅
    (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).obj
      WalkingParallelPair.one
[PROOFSTEP]
apply PreservesProduct.iso s
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ ∀ {X Y : WalkingParallelPair} (f : X ⟶ Y),
    (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map f ≫
        (WalkingParallelPair.casesOn Y (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom =
      (WalkingParallelPair.casesOn X (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
        (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map f
[PROOFSTEP]
rintro _ _ (_ | _)
[GOAL]
case left
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map WalkingParallelPairHom.left ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        WalkingParallelPairHom.left
[PROOFSTEP]
refine' limit.hom_ext (fun j => _)
[GOAL]
case left
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ ((parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map WalkingParallelPairHom.left ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
        (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
          WalkingParallelPairHom.left) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j
[PROOFSTEP]
dsimp [Equalizer.Presieve.firstMap, firstMap]
[GOAL]
case left
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ (s.map (Pi.lift fun x => Pi.π (fun f => P.obj (op f.fst)) x.fst ≫ P.map pullback.fst.op) ≫
        piComparison s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))) j =
    ((piComparison s fun f => P.obj (op f.fst)) ≫
        Pi.lift fun x => Pi.π (fun f => s.obj (P.obj (op f.fst))) x.fst ≫ s.map (P.map pullback.fst.op)) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))) j
[PROOFSTEP]
simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
[GOAL]
case left
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ s.map (Pi.π (fun f => P.obj (op f.fst)) j.as.fst) ≫ s.map (P.map pullback.fst.op) =
    (piComparison s fun f => P.obj (op f.fst)) ≫
      Pi.π (fun f => s.obj (P.obj (op f.fst))) j.as.fst ≫ s.map (P.map pullback.fst.op)
[PROOFSTEP]
rw [piComparison_comp_π_assoc]
[GOAL]
case right
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map WalkingParallelPairHom.right ≫
      (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom =
    (WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        WalkingParallelPairHom.right
[PROOFSTEP]
refine' limit.hom_ext (fun j => _)
[GOAL]
case right
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ ((parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map WalkingParallelPairHom.right ≫
        (WalkingParallelPair.casesOn WalkingParallelPair.one (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j =
    ((WalkingParallelPair.casesOn WalkingParallelPair.zero (PreservesProduct.iso s fun f => P.obj (op f.fst))
            (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
        (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
          WalkingParallelPairHom.right) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) j
[PROOFSTEP]
dsimp [Equalizer.Presieve.secondMap, secondMap]
[GOAL]
case right
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ (s.map (Pi.lift fun x => Pi.π (fun f => P.obj (op f.fst)) x.snd ≫ P.map pullback.snd.op) ≫
        piComparison s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))) j =
    ((piComparison s fun f => P.obj (op f.fst)) ≫
        Pi.lift fun x => Pi.π (fun f => s.obj (P.obj (op f.fst))) x.snd ≫ s.map (P.map pullback.snd.op)) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))) j
[PROOFSTEP]
simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
[GOAL]
case right
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ s.map (Pi.π (fun f => P.obj (op f.fst)) j.as.snd) ≫ s.map (P.map pullback.snd.op) =
    (piComparison s fun f => P.obj (op f.fst)) ≫
      Pi.π (fun f => s.obj (P.obj (op f.fst))) j.as.snd ≫ s.map (P.map pullback.snd.op)
[PROOFSTEP]
rw [piComparison_comp_π_assoc]
[GOAL]
case id
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
X✝ : WalkingParallelPair
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map (WalkingParallelPairHom.id X✝) ≫
      (WalkingParallelPair.casesOn X✝ (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom =
    (WalkingParallelPair.casesOn X✝ (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        (WalkingParallelPairHom.id X✝)
[PROOFSTEP]
dsimp
[GOAL]
case id
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
X✝ : WalkingParallelPair
⊢ (parallelPair (s.map (firstMap R P)) (s.map (secondMap R P))).map (𝟙 X✝) ≫
      (WalkingParallelPair.rec (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) X✝).hom =
    (WalkingParallelPair.rec (PreservesProduct.iso s fun f => P.obj (op f.fst))
          (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) X✝).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map (𝟙 X✝)
[PROOFSTEP]
simp
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (Cones.postcompose
          (NatIso.ofComponents fun X =>
              WalkingParallelPair.casesOn X (PreservesProduct.iso s fun f => P.obj (op f.fst))
                (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom).obj
      (Fork.ofι (s.map (forkMap R P))
        (_ : s.map (forkMap R P) ≫ s.map (firstMap R P) = s.map (forkMap R P) ≫ s.map (secondMap R P))) ≅
    Fork.ofι (Equalizer.forkMap (P ⋙ s) R)
      (_ :
        Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.firstMap (P ⋙ s) R =
          Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.secondMap (P ⋙ s) R)
[PROOFSTEP]
refine' Fork.ext (Iso.refl _) _
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (Iso.refl
          ((Cones.postcompose
                  (NatIso.ofComponents fun X =>
                      WalkingParallelPair.casesOn X (PreservesProduct.iso s fun f => P.obj (op f.fst))
                        (PreservesProduct.iso s fun fg =>
                          P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom).obj
              (Fork.ofι (s.map (forkMap R P))
                (_ :
                  s.map (forkMap R P) ≫ s.map (firstMap R P) = s.map (forkMap R P) ≫ s.map (secondMap R P)))).pt).hom ≫
      Fork.ι
        (Fork.ofι (Equalizer.forkMap (P ⋙ s) R)
          (_ :
            Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.firstMap (P ⋙ s) R =
              Equalizer.forkMap (P ⋙ s) R ≫ Equalizer.Presieve.secondMap (P ⋙ s) R)) =
    Fork.ι
      ((Cones.postcompose
            (NatIso.ofComponents fun X =>
                WalkingParallelPair.casesOn X (PreservesProduct.iso s fun f => P.obj (op f.fst))
                  (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd)))).hom).obj
        (Fork.ofι (s.map (forkMap R P))
          (_ : s.map (forkMap R P) ≫ s.map (firstMap R P) = s.map (forkMap R P) ≫ s.map (secondMap R P))))
[PROOFSTEP]
dsimp [Equalizer.forkMap, forkMap]
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P✝ : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasProducts A
inst✝² : HasProducts A'
inst✝¹ : HasPullbacks C
P : Cᵒᵖ ⥤ A
s : A ⥤ Type (max v₁ u₁)
inst✝ : (J : Type (max v₁ u₁)) → PreservesLimitsOfShape (Discrete J) s
U : C
R : Presieve U
⊢ (𝟙 (s.obj (P.obj (op U))) ≫ Pi.lift fun f => s.map (P.map (↑f.snd).op)) =
    Fork.ι
      ((Cones.postcompose
            (NatIso.ofComponents fun X =>
                WalkingParallelPair.rec (PreservesProduct.iso s fun f => P.obj (op f.fst))
                  (PreservesProduct.iso s fun fg => P.obj (op (Limits.pullback ↑fg.fst.snd ↑fg.snd.snd))) X).hom).obj
        (Fork.ofι (s.map (Pi.lift fun f => P.map (↑f.snd).op))
          (_ :
            s.map (Pi.lift fun f => P.map (↑f.snd).op) ≫ s.map (firstMap R P) =
              s.map (Pi.lift fun f => P.map (↑f.snd).op) ≫ s.map (secondMap R P))))
[PROOFSTEP]
simp [Fork.ι]
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
⊢ IsSheaf J P' ↔ IsSheaf' J P'
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
⊢ IsSheaf J P' → IsSheaf' J P'
[PROOFSTEP]
intro h U R hR
[GOAL]
case mp
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
refine' ⟨_⟩
[GOAL]
case mp
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
⊢ IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))
[PROOFSTEP]
apply coyonedaJointlyReflectsLimits
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
⊢ (X : A'ᵒᵖ) →
    IsLimit
      ((coyoneda.obj X).mapCone
        (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
intro X
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
X : A'ᵒᵖ
⊢ IsLimit
    ((coyoneda.obj X).mapCone
      (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
X : A'ᵒᵖ
q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) (generate R).arrows
⊢ IsLimit
    ((coyoneda.obj X).mapCone
      (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
rw [← Presieve.isSheafFor_iff_generate] at q 
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
X : A'ᵒᵖ
q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) R
⊢ IsLimit
    ((coyoneda.obj X).mapCone
      (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
rw [Equalizer.Presieve.sheaf_condition] at q 
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
X : A'ᵒᵖ
q :
  Nonempty
    (IsLimit
      (Fork.ofι (Equalizer.forkMap (P' ⋙ coyoneda.obj X) R)
        (_ :
          Equalizer.forkMap (P' ⋙ coyoneda.obj X) R ≫ Equalizer.Presieve.firstMap (P' ⋙ coyoneda.obj X) R =
            Equalizer.forkMap (P' ⋙ coyoneda.obj X) R ≫ Equalizer.Presieve.secondMap (P' ⋙ coyoneda.obj X) R)))
⊢ IsLimit
    ((coyoneda.obj X).mapCone
      (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
replace q := Classical.choice q
[GOAL]
case mp.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf J P'
U : C
R : Presieve U
hR : generate R ∈ GrothendieckTopology.sieves J U
X : A'ᵒᵖ
q :
  IsLimit
    (Fork.ofι (Equalizer.forkMap (P' ⋙ coyoneda.obj X) R)
      (_ :
        Equalizer.forkMap (P' ⋙ coyoneda.obj X) R ≫ Equalizer.Presieve.firstMap (P' ⋙ coyoneda.obj X) R =
          Equalizer.forkMap (P' ⋙ coyoneda.obj X) R ≫ Equalizer.Presieve.secondMap (P' ⋙ coyoneda.obj X) R))
⊢ IsLimit
    ((coyoneda.obj X).mapCone
      (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
apply (isSheafForIsSheafFor' _ _ _ _).symm q
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
⊢ IsSheaf' J P' → IsSheaf J P'
[PROOFSTEP]
intro h U X S hS
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
⊢ Presieve.IsSheafFor (P' ⋙ coyoneda.obj (op U)) S.arrows
[PROOFSTEP]
rw [Equalizer.Presieve.sheaf_condition]
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
⊢ Nonempty
    (IsLimit
      (Fork.ofι (Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows)
        (_ :
          Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows ≫
              Equalizer.Presieve.firstMap (P' ⋙ coyoneda.obj (op U)) S.arrows =
            Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows ≫
              Equalizer.Presieve.secondMap (P' ⋙ coyoneda.obj (op U)) S.arrows)))
[PROOFSTEP]
refine' ⟨_⟩
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
⊢ IsLimit
    (Fork.ofι (Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows)
      (_ :
        Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows ≫
            Equalizer.Presieve.firstMap (P' ⋙ coyoneda.obj (op U)) S.arrows =
          Equalizer.forkMap (P' ⋙ coyoneda.obj (op U)) S.arrows ≫
            Equalizer.Presieve.secondMap (P' ⋙ coyoneda.obj (op U)) S.arrows))
[PROOFSTEP]
refine' isSheafForIsSheafFor' _ _ _ _ _
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
⊢ IsLimit
    ((coyoneda.obj (op U)).mapCone
      (Fork.ofι (forkMap S.arrows P')
        (_ : forkMap S.arrows P' ≫ firstMap S.arrows P' = forkMap S.arrows P' ≫ secondMap S.arrows P')))
[PROOFSTEP]
letI := preservesSmallestLimitsOfPreservesLimits (coyoneda.obj (op U))
[GOAL]
case mpr
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
this : PreservesLimitsOfSize.{0, 0, max u₁ v₁, max u₁ v₁, u₂, (max u₁ v₁) + 1} (coyoneda.obj (op U)) :=
  preservesSmallestLimitsOfPreservesLimits (coyoneda.obj (op U))
⊢ IsLimit
    ((coyoneda.obj (op U)).mapCone
      (Fork.ofι (forkMap S.arrows P')
        (_ : forkMap S.arrows P' ≫ firstMap S.arrows P' = forkMap S.arrows P' ≫ secondMap S.arrows P')))
[PROOFSTEP]
apply isLimitOfPreserves
[GOAL]
case mpr.t
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
this : PreservesLimitsOfSize.{0, 0, max u₁ v₁, max u₁ v₁, u₂, (max u₁ v₁) + 1} (coyoneda.obj (op U)) :=
  preservesSmallestLimitsOfPreservesLimits (coyoneda.obj (op U))
⊢ IsLimit
    (Fork.ofι (forkMap S.arrows P')
      (_ : forkMap S.arrows P' ≫ firstMap S.arrows P' = forkMap S.arrows P' ≫ secondMap S.arrows P'))
[PROOFSTEP]
apply Classical.choice (h _ S.arrows _)
[GOAL]
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁴ : Category.{v₂, u₂} A
A' : Type u₂
inst✝³ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝² : HasProducts A
inst✝¹ : HasProducts A'
inst✝ : HasPullbacks C
h : IsSheaf' J P'
U : A'
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
this : PreservesLimitsOfSize.{0, 0, max u₁ v₁, max u₁ v₁, u₂, (max u₁ v₁) + 1} (coyoneda.obj (op U)) :=
  preservesSmallestLimitsOfPreservesLimits (coyoneda.obj (op U))
⊢ generate S.arrows ∈ GrothendieckTopology.sieves J X
[PROOFSTEP]
simpa
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
⊢ IsSheaf J P' ↔ IsSheaf J (P' ⋙ s)
[PROOFSTEP]
rw [isSheaf_iff_isSheaf', isSheaf_iff_isSheaf']
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
⊢ IsSheaf' J P' ↔ IsSheaf' J (P' ⋙ s)
[PROOFSTEP]
refine' forall_congr' (fun U => ball_congr (fun R _ => _))
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ↔
    Nonempty
      (IsLimit
        (Fork.ofι (forkMap R (P' ⋙ s))
          (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s))))
[PROOFSTEP]
letI : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ↔
    Nonempty
      (IsLimit
        (Fork.ofι (forkMap R (P' ⋙ s))
          (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s))))
[PROOFSTEP]
have : IsLimit (s.mapCone (Fork.ofι _ (w R P'))) ≃ IsLimit (Fork.ofι _ (w R (P' ⋙ s))) := isSheafForIsSheafFor' P' s U R
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ↔
    Nonempty
      (IsLimit
        (Fork.ofι (forkMap R (P' ⋙ s))
          (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s))))
[PROOFSTEP]
rw [← Equiv.nonempty_congr this]
[GOAL]
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ↔
    Nonempty
      (IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))))
[PROOFSTEP]
constructor
[GOAL]
case mp
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) →
    Nonempty
      (IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))))
[PROOFSTEP]
haveI := preservesSmallestLimitsOfPreservesLimits s
[GOAL]
case mp
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝¹ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this✝ :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
this : PreservesLimitsOfSize.{0, 0, max u₁ v₁, max u₁ v₁, u₂, max (u₁ + 1) (v₁ + 1)} s
⊢ Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) →
    Nonempty
      (IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))))
[PROOFSTEP]
exact Nonempty.map fun t => isLimitOfPreserves s t
[GOAL]
case mpr
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
⊢ Nonempty
      (IsLimit
        (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))) →
    Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
haveI := reflectsSmallestLimitsOfReflectsLimits s
[GOAL]
case mpr
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
A : Type u₂
inst✝⁵ : Category.{v₂, u₂} A
A' : Type u₂
inst✝⁴ : Category.{max v₁ u₁, u₂} A'
J : GrothendieckTopology C
U✝ : C
R✝ : Presieve U✝
P : Cᵒᵖ ⥤ A
P' : Cᵒᵖ ⥤ A'
inst✝³ : HasPullbacks C
s : A' ⥤ Type (max v₁ u₁)
inst✝² : HasLimits A'
inst✝¹ : PreservesLimits s
inst✝ : ReflectsIsomorphisms s
U : C
R : Presieve U
x✝ : generate R ∈ GrothendieckTopology.sieves J U
this✝¹ : ReflectsLimits s := reflectsLimitsOfReflectsIsomorphisms
this✝ :
  IsLimit (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P'))) ≃
    IsLimit
      (Fork.ofι (forkMap R (P' ⋙ s))
        (_ : forkMap R (P' ⋙ s) ≫ firstMap R (P' ⋙ s) = forkMap R (P' ⋙ s) ≫ secondMap R (P' ⋙ s)))
this : ReflectsLimitsOfSize.{0, 0, max u₁ v₁, max u₁ v₁, u₂, max (u₁ + 1) (v₁ + 1)} s
⊢ Nonempty
      (IsLimit
        (s.mapCone (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))) →
    Nonempty (IsLimit (Fork.ofι (forkMap R P') (_ : forkMap R P' ≫ firstMap R P' = forkMap R P' ≫ secondMap R P')))
[PROOFSTEP]
exact Nonempty.map fun t => isLimitOfReflects s t
