l3lab/ntp-mathlib huggingface dataset:
/-- (Implementation). An auxiliary lemma to convert between sheaf conditions. -/
def isSheafForIsSheafFor' (P : Cᵒᵖ ⥤ A) (s : A ⥤ Type max v₁ u₁)
    [∀ J, PreservesLimitsOfShape (Discrete.{max v₁ u₁} J) s] (U : C) (R : Presieve U) :
    IsLimit (s.mapCone (Fork.ofι _ (w R P))) ≃
      IsLimit (Fork.ofι _ (Equalizer.Presieve.w (P ⋙ s) R)) := by
  apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
  apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  · apply NatIso.ofComponents _ _
    · rintro (_ | _)
      · apply PreservesProduct.iso s
      · apply PreservesProduct.iso s
    · rintro _ _ (_ | _)
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.firstMap, firstMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.secondMap, secondMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · 

Proof state:
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'
B : Type u₃
inst✝⁴ : Category.{v₃, u₃} B
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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        (WalkingParallelPairHom.id X✝)

Next tactic:
dsimp
/-- (Implementation). An auxiliary lemma to convert between sheaf conditions. -/
def isSheafForIsSheafFor' (P : Cᵒᵖ ⥤ A) (s : A ⥤ Type max v₁ u₁)
    [∀ J, PreservesLimitsOfShape (Discrete.{max v₁ u₁} J) s] (U : C) (R : Presieve U) :
    IsLimit (s.mapCone (Fork.ofι _ (w R P))) ≃
      IsLimit (Fork.ofι _ (Equalizer.Presieve.w (P ⋙ s) R)) := by
  apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
  apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  · apply NatIso.ofComponents _ _
    · rintro (_ | _)
      · apply PreservesProduct.iso s
      · apply PreservesProduct.iso s
    · rintro _ _ (_ | _)
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.firstMap, firstMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.secondMap, secondMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · dsimp
        

Proof state:
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'
B : Type u₃
inst✝⁴ : Category.{v₃, u₃} B
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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd))) X✝).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map (𝟙 X✝)

Next tactic:
simp
/-- (Implementation). An auxiliary lemma to convert between sheaf conditions. -/
def isSheafForIsSheafFor' (P : Cᵒᵖ ⥤ A) (s : A ⥤ Type max v₁ u₁)
    [∀ J, PreservesLimitsOfShape (Discrete.{max v₁ u₁} J) s] (U : C) (R : Presieve U) :
    IsLimit (s.mapCone (Fork.ofι _ (w R P))) ≃
      IsLimit (Fork.ofι _ (Equalizer.Presieve.w (P ⋙ s) R)) := by
  apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
  apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  · apply NatIso.ofComponents _ _
    · rintro (_ | _)
      · apply PreservesProduct.iso s
      · apply PreservesProduct.iso s
    · rintro _ _ (_ | _)
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.firstMap, firstMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.secondMap, secondMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · dsimp
        simp
  · 

Proof state:
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'
B : Type u₃
inst✝⁴ : Category.{v₃, u₃} B
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.1.snd ↑fg.2.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)

Next tactic:
refine' Fork.ext (Iso.refl _) _
/-- (Implementation). An auxiliary lemma to convert between sheaf conditions. -/
def isSheafForIsSheafFor' (P : Cᵒᵖ ⥤ A) (s : A ⥤ Type max v₁ u₁)
    [∀ J, PreservesLimitsOfShape (Discrete.{max v₁ u₁} J) s] (U : C) (R : Presieve U) :
    IsLimit (s.mapCone (Fork.ofι _ (w R P))) ≃
      IsLimit (Fork.ofι _ (Equalizer.Presieve.w (P ⋙ s) R)) := by
  apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
  apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  · apply NatIso.ofComponents _ _
    · rintro (_ | _)
      · apply PreservesProduct.iso s
      · apply PreservesProduct.iso s
    · rintro _ _ (_ | _)
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.firstMap, firstMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.secondMap, secondMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · dsimp
        simp
  · refine' Fork.ext (Iso.refl _) _
    

Proof state:
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'
B : Type u₃
inst✝⁴ : Category.{v₃, u₃} B
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.1.snd ↑fg.2.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.1.snd ↑fg.2.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))))

Next tactic:
dsimp [Equalizer.forkMap, forkMap]
/-- (Implementation). An auxiliary lemma to convert between sheaf conditions. -/
def isSheafForIsSheafFor' (P : Cᵒᵖ ⥤ A) (s : A ⥤ Type max v₁ u₁)
    [∀ J, PreservesLimitsOfShape (Discrete.{max v₁ u₁} J) s] (U : C) (R : Presieve U) :
    IsLimit (s.mapCone (Fork.ofι _ (w R P))) ≃
      IsLimit (Fork.ofι _ (Equalizer.Presieve.w (P ⋙ s) R)) := by
  apply Equiv.trans (isLimitMapConeForkEquiv _ _) _
  apply (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  · apply NatIso.ofComponents _ _
    · rintro (_ | _)
      · apply PreservesProduct.iso s
      · apply PreservesProduct.iso s
    · rintro _ _ (_ | _)
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.firstMap, firstMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · refine' limit.hom_ext (fun j => _)
        dsimp [Equalizer.Presieve.secondMap, secondMap]
        simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
        rw [piComparison_comp_π_assoc]
      · dsimp
        simp
  · refine' Fork.ext (Iso.refl _) _
    dsimp [Equalizer.forkMap, forkMap]
    

Proof state:
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'
B : Type u₃
inst✝⁴ : Category.{v₃, u₃} B
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.1.snd ↑fg.2.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))))

Next tactic:
simp [Fork.ι]
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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'

Next tactic:
constructor
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · 

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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'

Next tactic:
intro h U R hR
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
refine' ⟨_⟩
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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'))

Next tactic:
apply coyonedaJointlyReflectsLimits
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
intro X
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
rw [← Presieve.isSheafFor_iff_generate] at q
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    rw [← Presieve.isSheafFor_iff_generate] at q
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
rw [Equalizer.Presieve.sheaf_condition] at q
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    rw [← Presieve.isSheafFor_iff_generate] at q
    rw [Equalizer.Presieve.sheaf_condition] at q
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
replace q := Classical.choice q
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    rw [← Presieve.isSheafFor_iff_generate] at q
    rw [Equalizer.Presieve.sheaf_condition] at q
    replace q := Classical.choice q
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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')))

Next tactic:
apply (isSheafForIsSheafFor' _ _ _ _).symm q
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    rw [← Presieve.isSheafFor_iff_generate] at q
    rw [Equalizer.Presieve.sheaf_condition] at q
    replace q := Classical.choice q
    apply (isSheafForIsSheafFor' _ _ _ _).symm q
  · 

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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'

Next tactic:
intro h U X S hS
/-- The equalizer definition of a sheaf given by `isSheaf'` is equivalent to `isSheaf`. -/
theorem isSheaf_iff_isSheaf' : IsSheaf J P' ↔ IsSheaf' J P' := by
  constructor
  · intro h U R hR
    refine' ⟨_⟩
    apply coyonedaJointlyReflectsLimits
    intro X
    have q : Presieve.IsSheafFor (P' ⋙ coyoneda.obj X) _ := h X.unop _ hR
    rw [← Presieve.isSheafFor_iff_generate] at q
    rw [Equalizer.Presieve.sheaf_condition] at q
    replace q := Classical.choice q
    apply (isSheafForIsSheafFor' _ _ _ _).symm q
  · intro h U X S hS
    

Proof state:
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'
B : Type u₃
inst✝³ : Category.{v₃, u₃} B
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

Next tactic:
rw [Equalizer.Presieve.sheaf_condition]