l3lab/ntp-mathlib huggingface dataset:
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
⊢ f ≫ 𝟙 Z = 𝟙 X ≫ f

Next tactic:
simp
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
⊢ f ≫ 𝟙 Z = 𝟙 X ≫ f

Next tactic:
simp
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
⊢ IsKernelPair pullback.fst
    (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
    (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))

Next tactic:
refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
⊢ pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫ pullback.fst =
    pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫ pullback.fst

Next tactic:
rw [pullback.lift_fst, pullback.lift_fst]
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · 

Proof state:
case refine'_1
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g

Next tactic:
simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · 

Proof state:
case refine'_2
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ (PullbackCone.fst s ≫ pullback.fst) ≫ f =
    lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
        (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
      a₁ ≫ g

Next tactic:
simp only [assoc, lift_fst_assoc, pullback.condition]
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · 

Proof state:
case refine'_3
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ (fun s =>
          pullback.lift (PullbackCone.fst s ≫ pullback.fst)
            (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
              (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
            (_ :
              (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                    (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                  a₁ ≫ g))
        s ≫
      PullbackCone.fst
        (PullbackCone.mk
          (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
          (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
          (_ :
            pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                pullback.fst =
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                pullback.fst)) =
    PullbackCone.fst s

Next tactic:
ext
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> 

Proof state:
case refine'_3.h₀
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ ((fun s =>
            pullback.lift (PullbackCone.fst s ≫ pullback.fst)
              (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
              (_ :
                (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                  lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                      (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                    a₁ ≫ g))
          s ≫
        PullbackCone.fst
          (PullbackCone.mk
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
            (_ :
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                  pullback.fst =
                pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                  pullback.fst))) ≫
      pullback.fst =
    PullbackCone.fst s ≫ pullback.fst

Next tactic:
simp
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> 

Proof state:
case refine'_3.h₁
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ ((fun s =>
            pullback.lift (PullbackCone.fst s ≫ pullback.fst)
              (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
              (_ :
                (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                  lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                      (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                    a₁ ≫ g))
          s ≫
        PullbackCone.fst
          (PullbackCone.mk
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
            (_ :
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                  pullback.fst =
                pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                  pullback.fst))) ≫
      pullback.snd =
    PullbackCone.fst s ≫ pullback.snd

Next tactic:
simp
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> simp
  · 

Proof state:
case refine'_4
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ (fun s =>
          pullback.lift (PullbackCone.fst s ≫ pullback.fst)
            (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
              (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
            (_ :
              (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                    (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                  a₁ ≫ g))
        s ≫
      PullbackCone.snd
        (PullbackCone.mk
          (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
          (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
          (_ :
            pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                pullback.fst =
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                pullback.fst)) =
    PullbackCone.snd s

Next tactic:
ext
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> simp
  · ext
    · 

Proof state:
case refine'_4.h₀
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ ((fun s =>
            pullback.lift (PullbackCone.fst s ≫ pullback.fst)
              (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
              (_ :
                (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                  lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                      (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                    a₁ ≫ g))
          s ≫
        PullbackCone.snd
          (PullbackCone.mk
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
            (_ :
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                  pullback.fst =
                pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                  pullback.fst))) ≫
      pullback.fst =
    PullbackCone.snd s ≫ pullback.fst

Next tactic:
simp [s.condition]
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> simp
  · ext
    · simp [s.condition]
    · 

Proof state:
case refine'_4.h₁
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
⊢ ((fun s =>
            pullback.lift (PullbackCone.fst s ≫ pullback.fst)
              (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
              (_ :
                (PullbackCone.fst s ≫ pullback.fst) ≫ f =
                  lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                      (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                    a₁ ≫ g))
          s ≫
        PullbackCone.snd
          (PullbackCone.mk
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
            (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
            (_ :
              pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                  pullback.fst =
                pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                  pullback.fst))) ≫
      pullback.snd =
    PullbackCone.snd s ≫ pullback.snd

Next tactic:
simp
/-- If `a₁ a₂ : A ⟶ Y` is a kernel pair for `g : Y ⟶ Z`, then `a₁ ×[Z] X` and `a₂ ×[Z] X`
(`A ×[Z] X ⟶ Y ×[Z] X`) is a kernel pair for `Y ×[Z] X ⟶ X`. -/
protected theorem pullback {X Y Z A : C} {g : Y ⟶ Z} {a₁ a₂ : A ⟶ Y} (h : IsKernelPair g a₁ a₂)
    (f : X ⟶ Z) [HasPullback f g] [HasPullback f (a₁ ≫ g)] :
    IsKernelPair (pullback.fst : pullback f g ⟶ X)
      (pullback.map f _ f _ (𝟙 X) a₁ (𝟙 Z) (by simp) <| Category.comp_id _)
      (pullback.map _ _ _ _ (𝟙 X) a₂ (𝟙 Z) (by simp) <| (Category.comp_id _).trans h.1.1) := by
  refine' ⟨⟨by rw [pullback.lift_fst, pullback.lift_fst]⟩, ⟨PullbackCone.isLimitAux _
    (fun s => pullback.lift (s.fst ≫ pullback.fst)
      (h.lift (s.fst ≫ pullback.snd) (s.snd ≫ pullback.snd) _ ) _) (fun s => _) (fun s => _)
        (fun s m hm => _)⟩⟩
  · simp_rw [Category.assoc, ← pullback.condition, ← Category.assoc, s.condition]
  · simp only [assoc, lift_fst_assoc, pullback.condition]
  · ext <;> simp
  · ext
    · simp [s.condition]
    · simp
  · 

Proof state:
case refine'_5
C : Type u
inst✝² : Category.{v, u} C
R X✝ Y✝ Z✝ : C
f✝ : X✝ ⟶ Y✝
a b : R ⟶ X✝
X Y Z A : C
g : Y ⟶ Z
a₁ a₂ : A ⟶ Y
h : IsKernelPair g a₁ a₂
f : X ⟶ Z
inst✝¹ : HasPullback f g
inst✝ : HasPullback f (a₁ ≫ g)
s : PullbackCone pullback.fst pullback.fst
m :
  s.pt ⟶
    (PullbackCone.mk (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
        (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
        (_ :
          pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
              pullback.fst =
            pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
              pullback.fst)).pt
hm :
  ∀ (j : WalkingCospan),
    m ≫
        (PullbackCone.mk
                (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g))
                (pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g))
                (_ :
                  pullback.map f (a₁ ≫ g) f g (𝟙 X) a₁ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₁ ≫ g) ≫
                      pullback.fst =
                    pullback.map f (a₁ ≫ g) f g (𝟙 X) a₂ (𝟙 Z) (_ : f ≫ 𝟙 Z = 𝟙 X ≫ f) (_ : (a₁ ≫ g) ≫ 𝟙 Z = a₂ ≫ g) ≫
                      pullback.fst)).π.app
          j =
      s.π.app j
⊢ m =
    (fun s =>
        pullback.lift (PullbackCone.fst s ≫ pullback.fst)
          (lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
            (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g))
          (_ :
            (PullbackCone.fst s ≫ pullback.fst) ≫ f =
              lift h (PullbackCone.fst s ≫ pullback.snd) (PullbackCone.snd s ≫ pullback.snd)
                  (_ : (PullbackCone.fst s ≫ pullback.snd) ≫ g = (PullbackCone.snd s ≫ pullback.snd) ≫ g) ≫
                a₁ ≫ g))
      s

Next tactic:
apply pullback.hom_ext