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 _)
  · 

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
⊢ parallelPair (s.map (firstMap R P)) (s.map (secondMap R P)) ≅
    parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)

Next tactic:
apply NatIso.ofComponents _ _
/-- (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 _ _
    · 

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
⊢ (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

Next tactic:
rintro (_ | _)
/-- (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 (_ | _)
      · 

Proof state:
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'
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
⊢ (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

Next tactic:
apply PreservesProduct.iso s
/-- (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
      · 

Proof state:
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'
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
⊢ (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

Next tactic:
apply PreservesProduct.iso s
/-- (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
    · 

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
⊢ ∀ {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.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 f

Next tactic:
rintro _ _ (_ | _)
/-- (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 _ _ (_ | _)
      · 

Proof state:
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'
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
⊢ (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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        WalkingParallelPairHom.left

Next tactic:
refine' limit.hom_ext (fun j => _)
/-- (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 => _)
        

Proof state:
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'
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
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.1.snd ↑fg.2.snd)))).hom) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd))) j

Next tactic:
dsimp [Equalizer.Presieve.firstMap, firstMap]
/-- (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]
        

Proof state:
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'
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
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.1 ≫ P.map pullback.fst.op) ≫
        piComparison s fun fg => P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd))) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd)))) j =
    ((piComparison s fun f => P.obj (op f.fst)) ≫
        Pi.lift fun fg => Pi.π (fun f => s.obj (P.obj (op f.fst))) fg.1 ≫ s.map (P.map pullback.fst.op)) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd)))) j

Next tactic:
simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
/-- (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]
        

Proof state:
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'
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
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ s.map (Pi.π (fun f => P.obj (op f.fst)) j.as.1) ≫ 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.1 ≫ s.map (P.map pullback.fst.op)

Next tactic:
rw [piComparison_comp_π_assoc]
/-- (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]
      · 

Proof state:
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'
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
⊢ (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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd)))).hom ≫
      (parallelPair (Equalizer.Presieve.firstMap (P ⋙ s) R) (Equalizer.Presieve.secondMap (P ⋙ s) R)).map
        WalkingParallelPairHom.right

Next tactic:
refine' limit.hom_ext (fun j => _)
/-- (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 => _)
        

Proof state:
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'
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
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.1.snd ↑fg.2.snd)))).hom) ≫
      limit.π (Discrete.functor fun fg => (P ⋙ s).obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.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.1.snd ↑fg.2.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.1.snd ↑fg.2.snd))) j

Next tactic:
dsimp [Equalizer.Presieve.secondMap, secondMap]
/-- (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]
        

Proof state:
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'
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
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.2 ≫ P.map pullback.snd.op) ≫
        piComparison s fun fg => P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd))) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd)))) j =
    ((piComparison s fun f => P.obj (op f.fst)) ≫
        Pi.lift fun fg => Pi.π (fun f => s.obj (P.obj (op f.fst))) fg.2 ≫ s.map (P.map pullback.snd.op)) ≫
      limit.π (Discrete.functor fun fg => s.obj (P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd)))) j

Next tactic:
simp only [limit.lift_π, map_lift_piComparison, assoc, Fan.mk_π_app, Functor.map_comp]
/-- (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]
        

Proof state:
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'
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
j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })
⊢ s.map (Pi.π (fun f => P.obj (op f.fst)) j.as.2) ≫ 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.2 ≫ s.map (P.map pullback.snd.op)

Next tactic:
rw [piComparison_comp_π_assoc]