l3lab/ntp-mathlib huggingface dataset:
/-- Lift the top along a Galois insertion -/
@[reducible]
def liftOrderTop [Preorder α] [OrderTop α] (gi : GaloisInsertion l u) :
    OrderTop β where
  top := gi.choice ⊤ <| le_top
  le_top := by
    

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝² : PartialOrder β
inst✝¹ : Preorder α
inst✝ : OrderTop α
gi : GaloisInsertion l u
⊢ ∀ (a : β), a ≤ ⊤

Next tactic:
simp only [gi.choice_eq]
/-- Lift the top along a Galois insertion -/
@[reducible]
def liftOrderTop [Preorder α] [OrderTop α] (gi : GaloisInsertion l u) :
    OrderTop β where
  top := gi.choice ⊤ <| le_top
  le_top := by
    simp only [gi.choice_eq]; 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝² : PartialOrder β
inst✝¹ : Preorder α
inst✝ : OrderTop α
gi : GaloisInsertion l u
⊢ ∀ (a : β), a ≤ l ⊤

Next tactic:
exact fun b => (gi.le_l_u b).trans (gi.gc.monotone_l le_top)
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ a ∈ s, sInf s ≤ a

Next tactic:
dsimp
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by dsimp; 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ a ∈ s, choice gi (sInf (u '' s)) (_ : u (l (sInf (u '' s))) ≤ sInf (u '' s)) ≤ a

Next tactic:
rw [gi.choice_eq]
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by dsimp; rw [gi.choice_eq]; 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ a ∈ s, l (sInf (u '' s)) ≤ a

Next tactic:
exact (gi.isGLB_of_u_image (isGLB_sInf _)).1
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by dsimp; rw [gi.choice_eq]; exact (gi.isGLB_of_u_image (isGLB_sInf _)).1
    le_sInf := fun s => by 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ (a : β), (∀ b ∈ s, a ≤ b) → a ≤ sInf s

Next tactic:
dsimp
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by dsimp; rw [gi.choice_eq]; exact (gi.isGLB_of_u_image (isGLB_sInf _)).1
    le_sInf := fun s => by dsimp; 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ (a : β), (∀ b ∈ s, a ≤ b) → a ≤ choice gi (sInf (u '' s)) (_ : u (l (sInf (u '' s))) ≤ sInf (u '' s))

Next tactic:
rw [gi.choice_eq]
/-- Lift all suprema and infima along a Galois insertion -/
@[reducible]
def liftCompleteLattice [CompleteLattice α] (gi : GaloisInsertion l u) : CompleteLattice β :=
  { gi.liftBoundedOrder, gi.liftLattice with
    sSup := fun s => l (sSup (u '' s))
    sSup_le := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).2
    le_sSup := fun s => (gi.isLUB_of_u_image (isLUB_sSup _)).1
    sInf := fun s =>
      gi.choice (sInf (u '' s)) <|
        (isGLB_sInf _).2 <|
          gi.gc.monotone_u.mem_lowerBounds_image (gi.isGLB_of_u_image <| isGLB_sInf _).1
    sInf_le := fun s => by dsimp; rw [gi.choice_eq]; exact (gi.isGLB_of_u_image (isGLB_sInf _)).1
    le_sInf := fun s => by dsimp; rw [gi.choice_eq]; 

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a a₁ a₂ : α
b b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder β
inst✝ : CompleteLattice α
gi : GaloisInsertion l u
src✝¹ : BoundedOrder β := liftBoundedOrder gi
src✝ : Lattice β := liftLattice gi
s : Set β
⊢ ∀ (a : β), (∀ b ∈ s, a ≤ b) → a ≤ l (sInf (u '' s))

Next tactic:
exact (gi.isGLB_of_u_image (isGLB_sInf _)).2
/-- Lift the infima along a Galois coinsertion -/
@[reducible]
def liftSemilatticeInf [SemilatticeInf β] (gi : GaloisCoinsertion l u) : SemilatticeInf α :=
  { ‹PartialOrder α› with
    inf_le_left := fun a b => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeInf β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b : α
⊢ a ⊓ b ≤ a

Next tactic:
exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).inf_le_left a b
/-- Lift the infima along a Galois coinsertion -/
@[reducible]
def liftSemilatticeInf [SemilatticeInf β] (gi : GaloisCoinsertion l u) : SemilatticeInf α :=
  { ‹PartialOrder α› with
    inf_le_left := fun a b => by
      exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).inf_le_left a b
    inf_le_right := fun a b => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeInf β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b : α
⊢ a ⊓ b ≤ b

Next tactic:
exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).inf_le_right a b
/-- Lift the infima along a Galois coinsertion -/
@[reducible]
def liftSemilatticeInf [SemilatticeInf β] (gi : GaloisCoinsertion l u) : SemilatticeInf α :=
  { ‹PartialOrder α› with
    inf_le_left := fun a b => by
      exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).inf_le_left a b
    inf_le_right := fun a b => by
      exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).inf_le_right a b
    le_inf := fun a b c => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeInf β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b c : α
⊢ a ≤ b → a ≤ c → a ≤ b ⊓ c

Next tactic:
exact (@OrderDual.semilatticeInf αᵒᵈ gi.dual.liftSemilatticeSup).le_inf a b c
/-- Lift the suprema along a Galois coinsertion -/
@[reducible]
def liftSemilatticeSup [SemilatticeSup β] (gi : GaloisCoinsertion l u) : SemilatticeSup α :=
  { ‹PartialOrder α› with
    sup := fun a b =>
      gi.choice (l a ⊔ l b) <|
        sup_le (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_left)
          (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_right)
    le_sup_left := fun a b => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeSup β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b : α
⊢ a ≤ a ⊔ b

Next tactic:
exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).le_sup_left a b
/-- Lift the suprema along a Galois coinsertion -/
@[reducible]
def liftSemilatticeSup [SemilatticeSup β] (gi : GaloisCoinsertion l u) : SemilatticeSup α :=
  { ‹PartialOrder α› with
    sup := fun a b =>
      gi.choice (l a ⊔ l b) <|
        sup_le (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_left)
          (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_right)
    le_sup_left := fun a b => by
      exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).le_sup_left a b
    le_sup_right := fun a b => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeSup β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b : α
⊢ b ≤ a ⊔ b

Next tactic:
exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).le_sup_right a b
/-- Lift the suprema along a Galois coinsertion -/
@[reducible]
def liftSemilatticeSup [SemilatticeSup β] (gi : GaloisCoinsertion l u) : SemilatticeSup α :=
  { ‹PartialOrder α› with
    sup := fun a b =>
      gi.choice (l a ⊔ l b) <|
        sup_le (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_left)
          (gi.gc.monotone_l <| gi.gc.le_u <| le_sup_right)
    le_sup_left := fun a b => by
      exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).le_sup_left a b
    le_sup_right := fun a b => by
      exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).le_sup_right a b
    sup_le := fun a b c => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
ι : Sort x
κ : ι → Sort u_1
a✝ a₁ a₂ : α
b✝ b₁ b₂ : β
l : α → β
u : β → α
inst✝¹ : PartialOrder α
inst✝ : SemilatticeSup β
gi : GaloisCoinsertion l u
src✝ : PartialOrder α := inst✝¹
a b c : α
⊢ a ≤ c → b ≤ c → a ⊔ b ≤ c

Next tactic:
exact (@OrderDual.semilatticeSup αᵒᵈ gi.dual.liftSemilatticeInf).sup_le a b c
@[reassoc (attr := simp)]
theorem equalizerSubobject_arrow :
    (equalizerSubobjectIso f g).hom ≫ equalizer.ι f g = (equalizerSubobject f g).arrow := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y Z : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
⊢ (equalizerSubobjectIso f g).hom ≫ equalizer.ι f g = arrow (equalizerSubobject f g)

Next tactic:
simp [equalizerSubobjectIso]
@[reassoc (attr := simp)]
theorem equalizerSubobject_arrow' :
    (equalizerSubobjectIso f g).inv ≫ (equalizerSubobject f g).arrow = equalizer.ι f g := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y Z : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
⊢ (equalizerSubobjectIso f g).inv ≫ arrow (equalizerSubobject f g) = equalizer.ι f g

Next tactic:
simp [equalizerSubobjectIso]
@[reassoc]
theorem equalizerSubobject_arrow_comp :
    (equalizerSubobject f g).arrow ≫ f = (equalizerSubobject f g).arrow ≫ g := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y Z : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
⊢ arrow (equalizerSubobject f g) ≫ f = arrow (equalizerSubobject f g) ≫ g

Next tactic:
rw [← equalizerSubobject_arrow, Category.assoc, Category.assoc, equalizer.condition]
theorem equalizerSubobject_factors {W : C} (h : W ⟶ X) (w : h ≫ f = h ≫ g) :
    (equalizerSubobject f g).Factors h :=
  ⟨equalizer.lift h w, by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y Z : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
W : C
h : W ⟶ X
w : h ≫ f = h ≫ g
⊢ equalizer.lift h w ≫ MonoOver.arrow (MonoOver.mk' (equalizer.ι f g)) = h

Next tactic:
simp
theorem equalizerSubobject_factors_iff {W : C} (h : W ⟶ X) :
    (equalizerSubobject f g).Factors h ↔ h ≫ f = h ≫ g :=
  ⟨fun w => by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
X Y Z : C
f g : X ⟶ Y
inst✝ : HasEqualizer f g
W : C
h : W ⟶ X
w : Factors (equalizerSubobject f g) h
⊢ h ≫ f = h ≫ g

Next tactic:
rw [← Subobject.factorThru_arrow _ _ w, Category.assoc, equalizerSubobject_arrow_comp,
      Category.assoc]
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem kernelSubobject_arrow :
    (kernelSubobjectIso f).hom ≫ kernel.ι f = (kernelSubobject f).arrow := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
⊢ (kernelSubobjectIso f).hom ≫ kernel.ι f = arrow (kernelSubobject f)

Next tactic:
simp [kernelSubobjectIso]
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem kernelSubobject_arrow' :
    (kernelSubobjectIso f).inv ≫ (kernelSubobject f).arrow = kernel.ι f := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
⊢ (kernelSubobjectIso f).inv ≫ arrow (kernelSubobject f) = kernel.ι f

Next tactic:
simp [kernelSubobjectIso]
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem kernelSubobject_arrow_comp : (kernelSubobject f).arrow ≫ f = 0 := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
⊢ arrow (kernelSubobject f) ≫ f = 0

Next tactic:
rw [← kernelSubobject_arrow]
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem kernelSubobject_arrow_comp : (kernelSubobject f).arrow ≫ f = 0 := by
  rw [← kernelSubobject_arrow]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
⊢ ((kernelSubobjectIso f).hom ≫ kernel.ι f) ≫ f = 0

Next tactic:
simp only [Category.assoc, kernel.condition, comp_zero]
theorem kernelSubobject_factors {W : C} (h : W ⟶ X) (w : h ≫ f = 0) :
    (kernelSubobject f).Factors h :=
  ⟨kernel.lift _ h w, by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
W : C
h : W ⟶ X
w : h ≫ f = 0
⊢ kernel.lift f h w ≫ MonoOver.arrow (MonoOver.mk' (kernel.ι f)) = h

Next tactic:
simp
theorem kernelSubobject_factors_iff {W : C} (h : W ⟶ X) :
    (kernelSubobject f).Factors h ↔ h ≫ f = 0 :=
  ⟨fun w => by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
W : C
h : W ⟶ X
w : Factors (kernelSubobject f) h
⊢ h ≫ f = 0

Next tactic:
rw [← Subobject.factorThru_arrow _ _ w, Category.assoc, kernelSubobject_arrow_comp,
      comp_zero]
@[simp]
theorem factorThruKernelSubobject_comp_arrow {W : C} (h : W ⟶ X) (w : h ≫ f = 0) :
    factorThruKernelSubobject f h w ≫ (kernelSubobject f).arrow = h := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
W : C
h : W ⟶ X
w : h ≫ f = 0
⊢ factorThruKernelSubobject f h w ≫ arrow (kernelSubobject f) = h

Next tactic:
dsimp [factorThruKernelSubobject]
@[simp]
theorem factorThruKernelSubobject_comp_arrow {W : C} (h : W ⟶ X) (w : h ≫ f = 0) :
    factorThruKernelSubobject f h w ≫ (kernelSubobject f).arrow = h := by
  dsimp [factorThruKernelSubobject]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
W : C
h : W ⟶ X
w : h ≫ f = 0
⊢ factorThru (kernelSubobject f) h (_ : Factors (kernelSubobject f) h) ≫ arrow (kernelSubobject f) = h

Next tactic:
simp
@[simp]
theorem factorThruKernelSubobject_comp_kernelSubobjectIso {W : C} (h : W ⟶ X) (w : h ≫ f = 0) :
    factorThruKernelSubobject f h w ≫ (kernelSubobjectIso f).hom = kernel.lift f h w :=
  (cancel_mono (kernel.ι f)).1 <| by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
W : C
h : W ⟶ X
w : h ≫ f = 0
⊢ (factorThruKernelSubobject f h w ≫ (kernelSubobjectIso f).hom) ≫ kernel.ι f = kernel.lift f h w ≫ kernel.ι f

Next tactic:
simp
/-- A commuting square induces a morphism between the kernel subobjects. -/
def kernelSubobjectMap (sq : Arrow.mk f ⟶ Arrow.mk f') :
    (kernelSubobject f : C) ⟶ (kernelSubobject f' : C) :=
  Subobject.factorThru _ ((kernelSubobject f).arrow ≫ sq.left)
    (kernelSubobject_factors _ _ (by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y Z : C
inst✝² : HasZeroMorphisms C
f : X ⟶ Y
inst✝¹ : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝ : HasKernel f'
sq : Arrow.mk f ⟶ Arrow.mk f'
⊢ (arrow (kernelSubobject f) ≫ sq.left) ≫ f' = 0

Next tactic:
simp [sq.w]
@[reassoc (attr := simp), elementwise (attr := simp)]
theorem kernelSubobjectMap_arrow (sq : Arrow.mk f ⟶ Arrow.mk f') :
    kernelSubobjectMap sq ≫ (kernelSubobject f').arrow = (kernelSubobject f).arrow ≫ sq.left := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y Z : C
inst✝² : HasZeroMorphisms C
f : X ⟶ Y
inst✝¹ : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝ : HasKernel f'
sq : Arrow.mk f ⟶ Arrow.mk f'
⊢ kernelSubobjectMap sq ≫ arrow (kernelSubobject f') = arrow (kernelSubobject f) ≫ sq.left

Next tactic:
simp [kernelSubobjectMap]
@[simp]
theorem kernelSubobjectMap_id : kernelSubobjectMap (𝟙 (Arrow.mk f)) = 𝟙 _ := by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y Z : C
inst✝² : HasZeroMorphisms C
f : X ⟶ Y
inst✝¹ : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝ : HasKernel f'
⊢ kernelSubobjectMap (𝟙 (Arrow.mk f)) = 𝟙 (underlying.obj (kernelSubobject f))

Next tactic:
aesop_cat
@[simp]
theorem kernelSubobjectMap_comp {X'' Y'' : C} {f'' : X'' ⟶ Y''} [HasKernel f'']
    (sq : Arrow.mk f ⟶ Arrow.mk f') (sq' : Arrow.mk f' ⟶ Arrow.mk f'') :
    kernelSubobjectMap (sq ≫ sq') = kernelSubobjectMap sq ≫ kernelSubobjectMap sq' := by
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z : C
inst✝³ : HasZeroMorphisms C
f : X ⟶ Y
inst✝² : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝¹ : HasKernel f'
X'' Y'' : C
f'' : X'' ⟶ Y''
inst✝ : HasKernel f''
sq : Arrow.mk f ⟶ Arrow.mk f'
sq' : Arrow.mk f' ⟶ Arrow.mk f''
⊢ kernelSubobjectMap (sq ≫ sq') = kernelSubobjectMap sq ≫ kernelSubobjectMap sq'

Next tactic:
aesop_cat
@[reassoc]
theorem kernel_map_comp_kernelSubobjectIso_inv (sq : Arrow.mk f ⟶ Arrow.mk f') :
    kernel.map f f' sq.1 sq.2 sq.3.symm ≫ (kernelSubobjectIso _).inv =
      (kernelSubobjectIso _).inv ≫ kernelSubobjectMap sq := by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y Z : C
inst✝² : HasZeroMorphisms C
f : X ⟶ Y
inst✝¹ : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝ : HasKernel f'
sq : Arrow.mk f ⟶ Arrow.mk f'
⊢ kernel.map f f' sq.left sq.right (_ : (Arrow.mk f).hom ≫ (𝟭 C).map sq.right = (𝟭 C).map sq.left ≫ (Arrow.mk f').hom) ≫
      (kernelSubobjectIso f').inv =
    (kernelSubobjectIso f).inv ≫ kernelSubobjectMap sq

Next tactic:
aesop_cat
@[reassoc]
theorem kernelSubobjectIso_comp_kernel_map (sq : Arrow.mk f ⟶ Arrow.mk f') :
    (kernelSubobjectIso _).hom ≫ kernel.map f f' sq.1 sq.2 sq.3.symm =
      kernelSubobjectMap sq ≫ (kernelSubobjectIso _).hom :=
  by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
X Y Z : C
inst✝² : HasZeroMorphisms C
f : X ⟶ Y
inst✝¹ : HasKernel f
X' Y' : C
f' : X' ⟶ Y'
inst✝ : HasKernel f'
sq : Arrow.mk f ⟶ Arrow.mk f'
⊢ (kernelSubobjectIso f).hom ≫
      kernel.map f f' sq.left sq.right
        (_ : (Arrow.mk f).hom ≫ (𝟭 C).map sq.right = (𝟭 C).map sq.left ≫ (Arrow.mk f').hom) =
    kernelSubobjectMap sq ≫ (kernelSubobjectIso f').hom

Next tactic:
simp [← Iso.comp_inv_eq, kernel_map_comp_kernelSubobjectIso_inv]
@[simp]
theorem kernelSubobject_zero {A B : C} : kernelSubobject (0 : A ⟶ B) = ⊤ :=
  (isIso_iff_mk_eq_top _).mp (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
A B : C
⊢ IsIso (kernel.ι 0)

Next tactic:
infer_instance
theorem le_kernelSubobject (A : Subobject X) (h : A.arrow ≫ f = 0) : A ≤ kernelSubobject f :=
  Subobject.le_mk_of_comm (kernel.lift f A.arrow h) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
X Y Z : C
inst✝¹ : HasZeroMorphisms C
f : X ⟶ Y
inst✝ : HasKernel f
A : Subobject X
h : arrow A ≫ f = 0
⊢ kernel.lift f (arrow A) h ≫ kernel.ι f = arrow A

Next tactic:
simp
@[simp]
theorem kernelSubobjectIsoComp_hom_arrow {X' : C} (f : X' ⟶ X) [IsIso f] (g : X ⟶ Y) [HasKernel g] :
    (kernelSubobjectIsoComp f g).hom ≫ (kernelSubobject g).arrow =
      (kernelSubobject (f ≫ g)).arrow ≫ f :=
  by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z : C
inst✝³ : HasZeroMorphisms C
f✝ : X ⟶ Y
inst✝² : HasKernel f✝
X' : C
f : X' ⟶ X
inst✝¹ : IsIso f
g : X ⟶ Y
inst✝ : HasKernel g
⊢ (kernelSubobjectIsoComp f g).hom ≫ arrow (kernelSubobject g) = arrow (kernelSubobject (f ≫ g)) ≫ f

Next tactic:
simp [kernelSubobjectIsoComp]
@[simp]
theorem kernelSubobjectIsoComp_inv_arrow {X' : C} (f : X' ⟶ X) [IsIso f] (g : X ⟶ Y) [HasKernel g] :
    (kernelSubobjectIsoComp f g).inv ≫ (kernelSubobject (f ≫ g)).arrow =
      (kernelSubobject g).arrow ≫ inv f :=
  by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z : C
inst✝³ : HasZeroMorphisms C
f✝ : X ⟶ Y
inst✝² : HasKernel f✝
X' : C
f : X' ⟶ X
inst✝¹ : IsIso f
g : X ⟶ Y
inst✝ : HasKernel g
⊢ (kernelSubobjectIsoComp f g).inv ≫ arrow (kernelSubobject (f ≫ g)) = arrow (kernelSubobject g) ≫ inv f

Next tactic:
simp [kernelSubobjectIsoComp]
/-- The kernel of `f` is always a smaller subobject than the kernel of `f ≫ h`. -/
theorem kernelSubobject_comp_le (f : X ⟶ Y) [HasKernel f] {Z : C} (h : Y ⟶ Z) [HasKernel (f ≫ h)] :
    kernelSubobject f ≤ kernelSubobject (f ≫ h) :=
  le_kernelSubobject _ _ (by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z✝ : C
inst✝³ : HasZeroMorphisms C
f✝ : X ⟶ Y
inst✝² : HasKernel f✝
f : X ⟶ Y
inst✝¹ : HasKernel f
Z : C
h : Y ⟶ Z
inst✝ : HasKernel (f ≫ h)
⊢ arrow (kernelSubobject f) ≫ f ≫ h = 0

Next tactic:
simp
/-- Postcomposing by a monomorphism does not change the kernel subobject. -/
@[simp]
theorem kernelSubobject_comp_mono (f : X ⟶ Y) [HasKernel f] {Z : C} (h : Y ⟶ Z) [Mono h] :
    kernelSubobject (f ≫ h) = kernelSubobject f :=
  le_antisymm (le_kernelSubobject _ _ ((cancel_mono h).mp (by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z✝ : C
inst✝³ : HasZeroMorphisms C
f✝ : X ⟶ Y
inst✝² : HasKernel f✝
f : X ⟶ Y
inst✝¹ : HasKernel f
Z : C
h : Y ⟶ Z
inst✝ : Mono h
⊢ (arrow (kernelSubobject (f ≫ h)) ≫ f) ≫ h = 0 ≫ h

Next tactic:
simp
instance kernelSubobject_comp_mono_isIso (f : X ⟶ Y) [HasKernel f] {Z : C} (h : Y ⟶ Z) [Mono h] :
    IsIso (Subobject.ofLE _ _ (kernelSubobject_comp_le f h)) := by
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
X Y Z✝ : C
inst✝³ : HasZeroMorphisms C
f✝ : X ⟶ Y
inst✝² : HasKernel f✝
f : X ⟶ Y
inst✝¹ : HasKernel f
Z : C
h : Y ⟶ Z
inst✝ : Mono h
⊢ IsIso (ofLE (kernelSubobject f) (kernelSubobject (f ≫ h)) (_ : kernelSubobject f ≤ kernelSubobject (f ≫ h)))

Next tactic:
rw [ofLE_mk_le_mk_of_comm (kernelCompMono f h).inv]