l3lab/ntp-mathlib huggingface dataset:
@[simp]
lemma star_le_one_iff {x : R} : star x ≤ 1 ↔ x ≤ 1 := by
  

Proof state:
R : Type u
inst✝² : Semiring R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
x : R
⊢ star x ≤ 1 ↔ x ≤ 1

Next tactic:
simpa using star_le_star_iff (x := x) (y := 1)
@[simp]
lemma one_lt_star_iff {x : R} : 1 < star x ↔ 1 < x := by
  

Proof state:
R : Type u
inst✝² : Semiring R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
x : R
⊢ 1 < star x ↔ 1 < x

Next tactic:
simpa using star_lt_star_iff (x := 1) (y := x)
@[simp]
lemma star_lt_one_iff {x : R} : star x < 1 ↔ x < 1 := by
  

Proof state:
R : Type u
inst✝² : Semiring R
inst✝¹ : PartialOrder R
inst✝ : StarOrderedRing R
x : R
⊢ star x < 1 ↔ x < 1

Next tactic:
simpa using star_lt_star_iff (x := x) (y := 1)
/--
(Implementation) Given the appropriate product and equalizer cones, build the cone for `F` which is
limiting if the given cones are also.
-/
@[simps]
def buildLimit : Cone F where
  pt := i.pt
  π :=
    { app := fun j => i.ι ≫ c₁.π.app ⟨_⟩
      naturality := fun j₁ j₂ f => by
        

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
j₁ j₂ : J
f : j₁ ⟶ j₂
⊢ ((Functor.const J).obj i.pt).map f ≫ (fun j => Fork.ι i ≫ c₁.π.app { as := j }) j₂ =
    (fun j => Fork.ι i ≫ c₁.π.app { as := j }) j₁ ≫ F.map f

Next tactic:
dsimp
/--
(Implementation) Given the appropriate product and equalizer cones, build the cone for `F` which is
limiting if the given cones are also.
-/
@[simps]
def buildLimit : Cone F where
  pt := i.pt
  π :=
    { app := fun j => i.ι ≫ c₁.π.app ⟨_⟩
      naturality := fun j₁ j₂ f => by
        dsimp
        

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
j₁ j₂ : J
f : j₁ ⟶ j₂
⊢ 𝟙 i.pt ≫ Fork.ι i ≫ c₁.π.app { as := j₂ } = (Fork.ι i ≫ c₁.π.app { as := j₁ }) ≫ F.map f

Next tactic:
rw [Category.id_comp, Category.assoc, ← hs ⟨⟨_, _⟩, f⟩, i.condition_assoc, ht]
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
⊢ q.pt ⟶ (buildLimit s t hs ht i).pt

Next tactic:
refine' hi.lift (Fork.ofι _ _)
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · 

Proof state:
case refine'_1
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
⊢ q.1 ⟶ c₁.pt

Next tactic:
refine' t₁.lift (Fan.mk _ fun j => _)
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      

Proof state:
case refine'_1
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
j : J
⊢ q.1 ⟶ F.obj j

Next tactic:
apply q.π.app j
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · 

Proof state:
case refine'_2
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
⊢ IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s = IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t

Next tactic:
apply t₂.hom_ext
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · apply t₂.hom_ext
      

Proof state:
case refine'_2
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
⊢ ∀ (j : Discrete ((p : J × J) × (p.1 ⟶ p.2))),
    (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s) ≫ c₂.π.app j =
      (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t) ≫ c₂.π.app j

Next tactic:
intro ⟨j⟩
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · apply t₂.hom_ext
      intro ⟨j⟩
      

Proof state:
case refine'_2
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
j : (p : J × J) × (p.1 ⟶ p.2)
⊢ (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s) ≫ c₂.π.app { as := j } =
    (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t) ≫ c₂.π.app { as := j }

Next tactic:
simp [hs, ht]
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · apply t₂.hom_ext
      intro ⟨j⟩
      simp [hs, ht]
  uniq q m w :=
    hi.hom_ext
      (i.equalizer_ext
        (t₁.hom_ext fun j => by
          cases' j with j
          simpa using w j))
  fac s j := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s✝ t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s✝ ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s✝ t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
s : Cone F
j : J
⊢ (fun q =>
          IsLimit.lift hi
            (Fork.ofι (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j))
              (_ :
                IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s✝ =
                  IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t)))
        s ≫
      (buildLimit s✝ t hs ht i).π.app j =
    s.π.app j

Next tactic:
simp
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · apply t₂.hom_ext
      intro ⟨j⟩
      simp [hs, ht]
  uniq q m w :=
    hi.hom_ext
      (i.equalizer_ext
        (t₁.hom_ext fun j => by
          

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
m : q.pt ⟶ (buildLimit s t hs ht i).pt
w : ∀ (j : J), m ≫ (buildLimit s t hs ht i).π.app j = q.π.app j
j : Discrete J
⊢ (m ≫ Fork.ι i) ≫ c₁.π.app j =
    ((fun q =>
            IsLimit.lift hi
              (Fork.ofι (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j))
                (_ :
                  IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s =
                    IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t)))
          q ≫
        Fork.ι i) ≫
      c₁.π.app j

Next tactic:
cases' j with j
/--
(Implementation) Show the cone constructed in `buildLimit` is limiting, provided the cones used in
its construction are.
-/
def buildIsLimit (t₁ : IsLimit c₁) (t₂ : IsLimit c₂) (hi : IsLimit i) :
    IsLimit (buildLimit s t hs ht i) where
  lift q := by
    refine' hi.lift (Fork.ofι _ _)
    · refine' t₁.lift (Fan.mk _ fun j => _)
      apply q.π.app j
    · apply t₂.hom_ext
      intro ⟨j⟩
      simp [hs, ht]
  uniq q m w :=
    hi.hom_ext
      (i.equalizer_ext
        (t₁.hom_ext fun j => by
          cases' j with j
          

Proof state:
case mk
C : Type u
inst✝¹ : Category.{v, u} C
J : Type w
inst✝ : SmallCategory J
F : J ⥤ C
c₁ : Fan F.obj
c₂ : Fan fun f => F.obj f.fst.2
s t : c₁.pt ⟶ c₂.pt
hs : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), s ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.1 } ≫ F.map f.snd
ht : ∀ (f : (p : J × J) × (p.1 ⟶ p.2)), t ≫ c₂.π.app { as := f } = c₁.π.app { as := f.fst.2 }
i : Fork s t
t₁ : IsLimit c₁
t₂ : IsLimit c₂
hi : IsLimit i
q : Cone F
m : q.pt ⟶ (buildLimit s t hs ht i).pt
w : ∀ (j : J), m ≫ (buildLimit s t hs ht i).π.app j = q.π.app j
j : J
⊢ (m ≫ Fork.ι i) ≫ c₁.π.app { as := j } =
    ((fun q =>
            IsLimit.lift hi
              (Fork.ofι (IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j))
                (_ :
                  IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ s =
                    IsLimit.lift t₁ (Fan.mk q.1 fun j => q.π.app j) ≫ t)))
          q ≫
        Fork.ι i) ≫
      c₁.π.app { as := j }

Next tactic:
simpa using w j
/-- Given the existence of the appropriate (possibly finite) products and equalizers,
we can construct a limit cone for `F`.
(This assumes the existence of all equalizers, which is technically stronger than needed.)
-/
noncomputable def limitConeOfEqualizerAndProduct (F : J ⥤ C) [HasLimit (Discrete.functor F.obj)]
    [HasLimit (Discrete.functor fun f : Σp : J × J, p.1 ⟶ p.2 => F.obj f.1.2)] [HasEqualizers C] :
    LimitCone F where
  cone := _
  isLimit :=
    buildIsLimit (Pi.lift fun f => limit.π (Discrete.functor F.obj) ⟨_⟩ ≫ F.map f.2)
      (Pi.lift fun f => limit.π (Discrete.functor F.obj) ⟨f.1.2⟩) (by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
J : Type w
inst✝³ : SmallCategory J
F : J ⥤ C
inst✝² : HasLimit (Discrete.functor F.obj)
inst✝¹ : HasLimit (Discrete.functor fun f => F.obj f.fst.2)
inst✝ : HasEqualizers C
⊢ ∀ (f : (p : J × J) × (p.1 ⟶ p.2)),
    (Pi.lift fun f => limit.π (Discrete.functor F.obj) { as := f.fst.1 } ≫ F.map f.snd) ≫
        (limit.cone (Discrete.functor fun f => F.obj f.fst.2)).π.app { as := f } =
      (limit.cone (Discrete.functor F.obj)).π.app { as := f.fst.1 } ≫ F.map f.snd

Next tactic:
simp
/-- Given the existence of the appropriate (possibly finite) products and equalizers,
we can construct a limit cone for `F`.
(This assumes the existence of all equalizers, which is technically stronger than needed.)
-/
noncomputable def limitConeOfEqualizerAndProduct (F : J ⥤ C) [HasLimit (Discrete.functor F.obj)]
    [HasLimit (Discrete.functor fun f : Σp : J × J, p.1 ⟶ p.2 => F.obj f.1.2)] [HasEqualizers C] :
    LimitCone F where
  cone := _
  isLimit :=
    buildIsLimit (Pi.lift fun f => limit.π (Discrete.functor F.obj) ⟨_⟩ ≫ F.map f.2)
      (Pi.lift fun f => limit.π (Discrete.functor F.obj) ⟨f.1.2⟩) (by simp) (by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
J : Type w
inst✝³ : SmallCategory J
F : J ⥤ C
inst✝² : HasLimit (Discrete.functor F.obj)
inst✝¹ : HasLimit (Discrete.functor fun f => F.obj f.fst.2)
inst✝ : HasEqualizers C
⊢ ∀ (f : (p : J × J) × (p.1 ⟶ p.2)),
    (Pi.lift fun f => limit.π (Discrete.functor F.obj) { as := f.fst.2 }) ≫
        (limit.cone (Discrete.functor fun f => F.obj f.fst.2)).π.app { as := f } =
      (limit.cone (Discrete.functor F.obj)).π.app { as := f.fst.2 }

Next tactic:
simp
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
⊢ PreservesLimit K G

Next tactic:
let P := ∏ K.obj
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
⊢ PreservesLimit K G

Next tactic:
let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
⊢ PreservesLimit K G

Next tactic:
let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.1 } ≫ K.map f.snd
⊢ PreservesLimit K G

Next tactic:
let t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨f.1.2⟩
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
    let t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨f.1.2⟩
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.1 } ≫ K.map f.snd
t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.2 }
⊢ PreservesLimit K G

Next tactic:
let I := equalizer s t
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
    let t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨f.1.2⟩
    let I := equalizer s t
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.1 } ≫ K.map f.snd
t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.2 }
I : C := equalizer s t
⊢ PreservesLimit K G

Next tactic:
let i : I ⟶ P := equalizer.ι s t
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
    let t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨f.1.2⟩
    let I := equalizer s t
    let i : I ⟶ P := equalizer.ι s t
    

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.1 } ≫ K.map f.snd
t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.2 }
I : C := equalizer s t
i : I ⟶ P := equalizer.ι s t
⊢ PreservesLimit K G

Next tactic:
apply
      preservesLimitOfPreservesLimitCone
        (buildIsLimit s t (by simp) (by simp) (limit.isLimit _) (limit.isLimit _)
          (limit.isLimit _))
/-- If a functor preserves equalizers and the appropriate products, it preserves limits. -/
noncomputable def preservesLimitOfPreservesEqualizersAndProduct : PreservesLimitsOfShape J G where
  preservesLimit {K} := by
    let P := ∏ K.obj
    let Q := ∏ fun f : Σp : J × J, p.fst ⟶ p.snd => K.obj f.1.2
    let s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨_⟩ ≫ K.map f.2
    let t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) ⟨f.1.2⟩
    let I := equalizer s t
    let i : I ⟶ P := equalizer.ι s t
    apply
      preservesLimitOfPreservesLimitCone
        (buildIsLimit s t (by 

Proof state:
C : Type u
inst✝⁸ : Category.{v, u} C
J : Type w
inst✝⁷ : SmallCategory J
D : Type u₂
inst✝⁶ : Category.{v₂, u₂} D
inst✝⁵ : HasLimitsOfShape (Discrete J) C
inst✝⁴ : HasLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) C
inst✝³ : HasEqualizers C
G : C ⥤ D
inst✝² : PreservesLimitsOfShape WalkingParallelPair G
inst✝¹ : PreservesLimitsOfShape (Discrete J) G
inst✝ : PreservesLimitsOfShape (Discrete ((p : J × J) × (p.1 ⟶ p.2))) G
K : J ⥤ C
P : C := ∏ K.obj
Q : C := ∏ fun f => K.obj f.fst.2
s : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.1 } ≫ K.map f.snd
t : P ⟶ Q := Pi.lift fun f => limit.π (Discrete.functor K.obj) { as := f.fst.2 }
I : C := equalizer s t
i : I ⟶ P := equalizer.ι s t
⊢ ∀ (f : (p : J × J) × (p.1 ⟶ p.2)),
    s ≫ (limit.cone (Discrete.functor fun f => K.obj f.fst.2)).π.app { as := f } =
      (limit.cone (Discrete.functor K.obj)).π.app { as := f.fst.1 } ≫ K.map f.snd

Next tactic:
simp