l3lab/ntp-mathlib huggingface dataset:
@[reassoc]
theorem p_comm {P Q : Karoubi C} (f : Hom P Q) : P.p ≫ f.f = f.f ≫ Q.p := by 

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f : Hom P Q
⊢ P.p ≫ f.f = f.f ≫ Q.p

Next tactic:
rw [p_comp, comp_p]
theorem comp_proof {P Q R : Karoubi C} (g : Hom Q R) (f : Hom P Q) :
    f.f ≫ g.f = P.p ≫ (f.f ≫ g.f) ≫ R.p := by 

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q R : Karoubi C
g : Hom Q R
f : Hom P Q
⊢ f.f ≫ g.f = P.p ≫ (f.f ≫ g.f) ≫ R.p

Next tactic:
rw [assoc, comp_p, ← assoc, p_comp]
/-- The category structure on the karoubi envelope of a category. -/
instance : Category (Karoubi C) where
  Hom := Karoubi.Hom
  id P := ⟨P.p, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.11641, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p ≫ P.p

Next tactic:
repeat' rw [P.idem]
/-- The category structure on the karoubi envelope of a category. -/
instance : Category (Karoubi C) where
  Hom := Karoubi.Hom
  id P := ⟨P.p, by repeat' 

Proof state:
C : Type u_1
inst✝ : Category.{?u.11641, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p ≫ P.p

Next tactic:
rw [P.idem]
/-- The category structure on the karoubi envelope of a category. -/
instance : Category (Karoubi C) where
  Hom := Karoubi.Hom
  id P := ⟨P.p, by repeat' 

Proof state:
C : Type u_1
inst✝ : Category.{?u.11641, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p

Next tactic:
rw [P.idem]
@[simp]
theorem hom_ext_iff {P Q : Karoubi C} {f g : P ⟶ Q} : f = g ↔ f.f = g.f := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f g : P ⟶ Q
⊢ f = g ↔ f.f = g.f

Next tactic:
constructor
@[simp]
theorem hom_ext_iff {P Q : Karoubi C} {f g : P ⟶ Q} : f = g ↔ f.f = g.f := by
  constructor
  · 

Proof state:
case mp
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f g : P ⟶ Q
⊢ f = g → f.f = g.f

Next tactic:
intro h
@[simp]
theorem hom_ext_iff {P Q : Karoubi C} {f g : P ⟶ Q} : f = g ↔ f.f = g.f := by
  constructor
  · intro h
    

Proof state:
case mp
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f g : P ⟶ Q
h : f = g
⊢ f.f = g.f

Next tactic:
rw [h]
@[simp]
theorem hom_ext_iff {P Q : Karoubi C} {f g : P ⟶ Q} : f = g ↔ f.f = g.f := by
  constructor
  · intro h
    rw [h]
  · 

Proof state:
case mpr
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f g : P ⟶ Q
⊢ f.f = g.f → f = g

Next tactic:
apply Hom.ext
@[ext]
theorem hom_ext {P Q : Karoubi C} (f g : P ⟶ Q) (h : f.f = g.f) : f = g := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f g : P ⟶ Q
h : f.f = g.f
⊢ f = g

Next tactic:
simpa [hom_ext_iff] using h
@[simp]
theorem id_eq {P : Karoubi C} : 𝟙 P = ⟨P.p, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.15877, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p ≫ P.p

Next tactic:
repeat' rw [P.idem]
@[simp]
theorem id_eq {P : Karoubi C} : 𝟙 P = ⟨P.p, by repeat' 

Proof state:
C : Type u_1
inst✝ : Category.{?u.15877, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p ≫ P.p

Next tactic:
rw [P.idem]
@[simp]
theorem id_eq {P : Karoubi C} : 𝟙 P = ⟨P.p, by repeat' 

Proof state:
C : Type u_1
inst✝ : Category.{?u.15877, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p

Next tactic:
rw [P.idem]
/-- It is possible to coerce an object of `C` into an object of `Karoubi C`.
See also the functor `toKaroubi`. -/
instance coe : CoeTC C (Karoubi C) :=
  ⟨fun X => ⟨X, 𝟙 X, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.16188, u_1} C
X : C
⊢ 𝟙 X ≫ 𝟙 X = 𝟙 X

Next tactic:
rw [comp_id]
@[simp]
theorem eqToHom_f {P Q : Karoubi C} (h : P = Q) :
    Karoubi.Hom.f (eqToHom h) = P.p ≫ eqToHom (congr_arg Karoubi.X h) := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
h : P = Q
⊢ (eqToHom h).f = P.p ≫ eqToHom (_ : P.X = Q.X)

Next tactic:
subst h
@[simp]
theorem eqToHom_f {P Q : Karoubi C} (h : P = Q) :
    Karoubi.Hom.f (eqToHom h) = P.p ≫ eqToHom (congr_arg Karoubi.X h) := by
  subst h
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P : Karoubi C
⊢ (eqToHom (_ : P = P)).f = P.p ≫ eqToHom (_ : P.X = P.X)

Next tactic:
simp only [eqToHom_refl, Karoubi.id_eq, comp_id]
/-- The obvious fully faithful functor `toKaroubi` sends an object `X : C` to the obvious
formal direct factor of `X` given by `𝟙 X`. -/
@[simps]
def toKaroubi : C ⥤ Karoubi C where
  obj X := ⟨X, 𝟙 X, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.18656, u_1} C
X : C
⊢ 𝟙 X ≫ 𝟙 X = 𝟙 X

Next tactic:
rw [comp_id]
/-- The obvious fully faithful functor `toKaroubi` sends an object `X : C` to the obvious
formal direct factor of `X` given by `𝟙 X`. -/
@[simps]
def toKaroubi : C ⥤ Karoubi C where
  obj X := ⟨X, 𝟙 X, by rw [comp_id]⟩
  map f := ⟨f, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.18656, u_1} C
X✝ Y✝ : C
f : X✝ ⟶ Y✝
⊢ f = ((fun X => Karoubi.mk X (𝟙 X)) X✝).p ≫ f ≫ ((fun X => Karoubi.mk X (𝟙 X)) Y✝).p

Next tactic:
simp only [comp_id, id_comp]
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f g : P ⟶ Q
⊢ f.f + g.f = P.p ≫ (f.f + g.f) ≫ Q.p

Next tactic:
rw [add_comp, comp_add, ← f.comm, ← g.comm]
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f g h' : P ⟶ Q
⊢ f + g + h' = f + (g + h')

Next tactic:
ext
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f g h' : P ⟶ Q
⊢ (f + g + h').f = (f + (g + h')).f

Next tactic:
apply add_assoc
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
⊢ 0 = P.p ≫ 0 ≫ Q.p

Next tactic:
simp only [comp_zero, zero_comp]
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ 0 + f = f

Next tactic:
ext
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ (0 + f).f = f.f

Next tactic:
apply zero_add
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ f + 0 = f

Next tactic:
ext
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ (f + 0).f = f.f

Next tactic:
apply add_zero
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    apply add_assoc
  add_comm f g := by
    ext
    apply add_comm
  neg f := ⟨-f.f, by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ -f.f = P.p ≫ (-f.f) ≫ Q.p

Next tactic:
simpa only [neg_comp, comp_neg, neg_inj] using f.comm
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    apply add_assoc
  add_comm f g := by
    ext
    apply add_comm
  neg f := ⟨-f.f, by simpa only [neg_comp, comp_neg, neg_inj] using f.comm⟩
  add_left_neg f := by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ -f + f = 0

Next tactic:
ext
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    apply add_assoc
  add_comm f g := by
    ext
    apply add_comm
  neg f := ⟨-f.f, by simpa only [neg_comp, comp_neg, neg_inj] using f.comm⟩
  add_left_neg f := by
    ext
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f : P ⟶ Q
⊢ (-f + f).f = 0.f

Next tactic:
apply add_left_neg
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    apply add_assoc
  add_comm f g := by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f g : P ⟶ Q
⊢ f + g = g + f

Next tactic:
ext
@[simps add zero neg]
instance instAddCommGroupHom [Preadditive C] {P Q : Karoubi C} : AddCommGroup (P ⟶ Q) where
  add f g :=
    ⟨f.f + g.f, by rw [add_comp, comp_add, ← f.comm, ← g.comm]⟩
  zero := ⟨0, by simp only [comp_zero, zero_comp]⟩
  zero_add f := by
    ext
    apply zero_add
  add_zero f := by
    ext
    apply add_zero
  add_assoc f g h' := by
    ext
    apply add_assoc
  add_comm f g := by
    ext
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.25937, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
f g : P ⟶ Q
⊢ (f + g).f = (g + f).f

Next tactic:
apply add_comm
/-- The category `Karoubi C` is preadditive if `C` is. -/
instance [Preadditive C] : Preadditive (Karoubi C) where
  homGroup P Q := by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.36244, u_1} C
inst✝ : Preadditive C
P Q : Karoubi C
⊢ AddCommGroup (P ⟶ Q)

Next tactic:
infer_instance
instance : IsIdempotentComplete (Karoubi C) := by
  

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
⊢ IsIdempotentComplete (Karoubi C)

Next tactic:
refine' ⟨_⟩
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
⊢ ∀ (X : Karoubi C) (p : X ⟶ X), p ≫ p = p → ∃ Y i e, i ≫ e = 𝟙 Y ∧ e ≫ i = p

Next tactic:
intro P p hp
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p ≫ p = p
⊢ ∃ Y i e, i ≫ e = 𝟙 Y ∧ e ≫ i = p

Next tactic:
simp only [hom_ext_iff, comp_f] at hp
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ ∃ Y i e, i ≫ e = 𝟙 Y ∧ e ≫ i = p

Next tactic:
use ⟨P.X, p.f, hp⟩
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  use ⟨P.X, p.f, hp⟩
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ ∃ i e, i ≫ e = 𝟙 (Karoubi.mk P.X p.f) ∧ e ≫ i = p

Next tactic:
use ⟨p.f, by rw [comp_p p, hp]⟩
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  use ⟨P.X, p.f, hp⟩
  use ⟨p.f, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ p.f = (Karoubi.mk P.X p.f).p ≫ p.f ≫ P.p

Next tactic:
rw [comp_p p, hp]
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  use ⟨P.X, p.f, hp⟩
  use ⟨p.f, by rw [comp_p p, hp]⟩
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ ∃ e, Hom.mk p.f ≫ e = 𝟙 (Karoubi.mk P.X p.f) ∧ e ≫ Hom.mk p.f = p

Next tactic:
use ⟨p.f, by rw [hp, p_comp p]⟩
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  use ⟨P.X, p.f, hp⟩
  use ⟨p.f, by rw [comp_p p, hp]⟩
  use ⟨p.f, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ p.f = P.p ≫ p.f ≫ (Karoubi.mk P.X p.f).p

Next tactic:
rw [hp, p_comp p]
instance : IsIdempotentComplete (Karoubi C) := by
  refine' ⟨_⟩
  intro P p hp
  simp only [hom_ext_iff, comp_f] at hp
  use ⟨P.X, p.f, hp⟩
  use ⟨p.f, by rw [comp_p p, hp]⟩
  use ⟨p.f, by rw [hp, p_comp p]⟩
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{?u.39848, u_1} C
P : Karoubi C
p : P ⟶ P
hp : p.f ≫ p.f = p.f
⊢ Hom.mk p.f ≫ Hom.mk p.f = 𝟙 (Karoubi.mk P.X p.f) ∧ Hom.mk p.f ≫ Hom.mk p.f = p

Next tactic:
simp [hp]
instance [IsIdempotentComplete C] : EssSurj (toKaroubi C) :=
  ⟨fun P => by
    

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.41083, u_1} C
inst✝ : IsIdempotentComplete C
P : Karoubi C
⊢ P ∈ Functor.essImage (toKaroubi C)

Next tactic:
rcases IsIdempotentComplete.idempotents_split P.X P.p P.idem with ⟨Y, i, e, ⟨h₁, h₂⟩⟩
instance [IsIdempotentComplete C] : EssSurj (toKaroubi C) :=
  ⟨fun P => by
    rcases IsIdempotentComplete.idempotents_split P.X P.p P.idem with ⟨Y, i, e, ⟨h₁, h₂⟩⟩
    

Proof state:
case intro.intro.intro.intro
C : Type u_1
inst✝¹ : Category.{?u.41083, u_1} C
inst✝ : IsIdempotentComplete C
P : Karoubi C
Y : C
i : Y ⟶ P.X
e : P.X ⟶ Y
h₁ : i ≫ e = 𝟙 Y
h₂ : e ≫ i = P.p
⊢ P ∈ Functor.essImage (toKaroubi C)

Next tactic:
use Y
instance [IsIdempotentComplete C] : EssSurj (toKaroubi C) :=
  ⟨fun P => by
    rcases IsIdempotentComplete.idempotents_split P.X P.p P.idem with ⟨Y, i, e, ⟨h₁, h₂⟩⟩
    use Y
    

Proof state:
case h
C : Type u_1
inst✝¹ : Category.{?u.41083, u_1} C
inst✝ : IsIdempotentComplete C
P : Karoubi C
Y : C
i : Y ⟶ P.X
e : P.X ⟶ Y
h₁ : i ≫ e = 𝟙 Y
h₂ : e ≫ i = P.p
⊢ Nonempty ((toKaroubi C).obj Y ≅ P)

Next tactic:
exact
      Nonempty.intro
        { hom := ⟨i, by erw [id_comp, ← h₂, ← assoc, h₁, id_comp]⟩
          inv := ⟨e, by erw [comp_id, ← h₂, assoc, h₁, comp_id]⟩ }
instance [IsIdempotentComplete C] : EssSurj (toKaroubi C) :=
  ⟨fun P => by
    rcases IsIdempotentComplete.idempotents_split P.X P.p P.idem with ⟨Y, i, e, ⟨h₁, h₂⟩⟩
    use Y
    exact
      Nonempty.intro
        { hom := ⟨i, by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.41083, u_1} C
inst✝ : IsIdempotentComplete C
P : Karoubi C
Y : C
i : Y ⟶ P.X
e : P.X ⟶ Y
h₁ : i ≫ e = 𝟙 Y
h₂ : e ≫ i = P.p
⊢ i = ((toKaroubi C).obj Y).p ≫ i ≫ P.p

Next tactic:
erw [id_comp, ← h₂, ← assoc, h₁, id_comp]
instance [IsIdempotentComplete C] : EssSurj (toKaroubi C) :=
  ⟨fun P => by
    rcases IsIdempotentComplete.idempotents_split P.X P.p P.idem with ⟨Y, i, e, ⟨h₁, h₂⟩⟩
    use Y
    exact
      Nonempty.intro
        { hom := ⟨i, by erw [id_comp, ← h₂, ← assoc, h₁, id_comp]⟩
          inv := ⟨e, by 

Proof state:
C : Type u_1
inst✝¹ : Category.{?u.41083, u_1} C
inst✝ : IsIdempotentComplete C
P : Karoubi C
Y : C
i : Y ⟶ P.X
e : P.X ⟶ Y
h₁ : i ≫ e = 𝟙 Y
h₂ : e ≫ i = P.p
⊢ e = P.p ≫ e ≫ ((toKaroubi C).obj Y).p

Next tactic:
erw [comp_id, ← h₂, assoc, h₁, comp_id]
/-- The split mono which appears in the factorisation `decompId P`. -/
@[simps]
def decompId_i (P : Karoubi C) : P ⟶ P.X :=
  ⟨P.p, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.46684, u_1} C
P : Karoubi C
⊢ P.p = P.p ≫ P.p ≫ (mk P.X (𝟙 P.X)).p

Next tactic:
erw [coe_p, comp_id, P.idem]
/-- The split epi which appears in the factorisation `decompId P`. -/
@[simps]
def decompId_p (P : Karoubi C) : (P.X : Karoubi C) ⟶ P :=
  ⟨P.p, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.48333, u_1} C
P : Karoubi C
⊢ P.p = (mk P.X (𝟙 P.X)).p ≫ P.p ≫ P.p

Next tactic:
erw [coe_p, id_comp, P.idem]
/-- The formal direct factor of `P.X` given by the idempotent `P.p` in the category `C`
is actually a direct factor in the category `Karoubi C`. -/
@[reassoc]
theorem decompId (P : Karoubi C) : 𝟙 P = decompId_i P ≫ decompId_p P := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P : Karoubi C
⊢ 𝟙 P = decompId_i P ≫ decompId_p P

Next tactic:
ext
/-- The formal direct factor of `P.X` given by the idempotent `P.p` in the category `C`
is actually a direct factor in the category `Karoubi C`. -/
@[reassoc]
theorem decompId (P : Karoubi C) : 𝟙 P = decompId_i P ≫ decompId_p P := by
  ext
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P : Karoubi C
⊢ (𝟙 P).f = (decompId_i P ≫ decompId_p P).f

Next tactic:
simp only [comp_f, id_eq, P.idem, decompId_i, decompId_p]
theorem decomp_p (P : Karoubi C) : (toKaroubi C).map P.p = decompId_p P ≫ decompId_i P := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P : Karoubi C
⊢ (toKaroubi C).map P.p = decompId_p P ≫ decompId_i P

Next tactic:
ext
theorem decomp_p (P : Karoubi C) : (toKaroubi C).map P.p = decompId_p P ≫ decompId_i P := by
  ext
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P : Karoubi C
⊢ ((toKaroubi C).map P.p).f = (decompId_p P ≫ decompId_i P).f

Next tactic:
simp only [comp_f, decompId_p_f, decompId_i_f, P.idem, toKaroubi_map_f]
theorem decompId_i_toKaroubi (X : C) : decompId_i ((toKaroubi C).obj X) = 𝟙 _ := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X : C
⊢ decompId_i ((toKaroubi C).obj X) = 𝟙 ((toKaroubi C).obj X)

Next tactic:
rfl
theorem decompId_p_toKaroubi (X : C) : decompId_p ((toKaroubi C).obj X) = 𝟙 _ := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X : C
⊢ decompId_p ((toKaroubi C).obj X) = 𝟙 (mk ((toKaroubi C).obj X).X (𝟙 ((toKaroubi C).obj X).X))

Next tactic:
rfl
theorem decompId_i_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    f ≫ decompId_i Q = decompId_i P ≫ (by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.51404, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ mk P.X (𝟙 P.X) ⟶ mk Q.X (𝟙 Q.X)

Next tactic:
exact Hom.mk f.f (by simp)
theorem decompId_i_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    f ≫ decompId_i Q = decompId_i P ≫ (by exact Hom.mk f.f (by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.51404, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ f.f = (mk P.X (𝟙 P.X)).p ≫ f.f ≫ (mk Q.X (𝟙 Q.X)).p

Next tactic:
simp
theorem decompId_i_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    f ≫ decompId_i Q = decompId_i P ≫ (by exact Hom.mk f.f (by simp)) := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ f ≫ decompId_i Q = decompId_i P ≫ Hom.mk f.f

Next tactic:
aesop_cat
theorem decompId_p_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    decompId_p P ≫ f = (by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.52543, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ mk P.X (𝟙 P.X) ⟶ mk Q.X (𝟙 Q.X)

Next tactic:
exact Hom.mk f.f (by simp)
theorem decompId_p_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    decompId_p P ≫ f = (by exact Hom.mk f.f (by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.52543, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ f.f = (mk P.X (𝟙 P.X)).p ≫ f.f ≫ (mk Q.X (𝟙 Q.X)).p

Next tactic:
simp
theorem decompId_p_naturality {P Q : Karoubi C} (f : P ⟶ Q) :
    decompId_p P ≫ f = (by exact Hom.mk f.f (by simp)) ≫ decompId_p Q := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
P Q : Karoubi C
f : P ⟶ Q
⊢ decompId_p P ≫ f = Hom.mk f.f ≫ decompId_p Q

Next tactic:
aesop_cat
theorem relabel_id (t : L.Term α) : t.relabel id = t := by
  

Proof state:
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
t : Term L α
⊢ relabel id t = t

Next tactic:
induction' t with _ _ _ _ ih
theorem relabel_id (t : L.Term α) : t.relabel id = t := by
  induction' t with _ _ _ _ ih
  · 

Proof state:
case var
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
_a✝ : α
⊢ relabel id (var _a✝) = var _a✝

Next tactic:
rfl
theorem relabel_id (t : L.Term α) : t.relabel id = t := by
  induction' t with _ _ _ _ ih
  · rfl
  · 

Proof state:
case func
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
l✝ : ℕ
_f✝ : Functions L l✝
_ts✝ : Fin l✝ → Term L α
ih : ∀ (a : Fin l✝), relabel id (_ts✝ a) = _ts✝ a
⊢ relabel id (func _f✝ _ts✝) = func _f✝ _ts✝

Next tactic:
simp [ih]
@[simp]
theorem relabel_relabel (f : α → β) (g : β → γ) (t : L.Term α) :
    (t.relabel f).relabel g = t.relabel (g ∘ f) := by
  

Proof state:
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
f : α → β
g : β → γ
t : Term L α
⊢ relabel g (relabel f t) = relabel (g ∘ f) t

Next tactic:
induction' t with _ _ _ _ ih
@[simp]
theorem relabel_relabel (f : α → β) (g : β → γ) (t : L.Term α) :
    (t.relabel f).relabel g = t.relabel (g ∘ f) := by
  induction' t with _ _ _ _ ih
  · 

Proof state:
case var
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
f : α → β
g : β → γ
_a✝ : α
⊢ relabel g (relabel f (var _a✝)) = relabel (g ∘ f) (var _a✝)

Next tactic:
rfl
@[simp]
theorem relabel_relabel (f : α → β) (g : β → γ) (t : L.Term α) :
    (t.relabel f).relabel g = t.relabel (g ∘ f) := by
  induction' t with _ _ _ _ ih
  · rfl
  · 

Proof state:
case func
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
f : α → β
g : β → γ
l✝ : ℕ
_f✝ : Functions L l✝
_ts✝ : Fin l✝ → Term L α
ih : ∀ (a : Fin l✝), relabel g (relabel f (_ts✝ a)) = relabel (g ∘ f) (_ts✝ a)
⊢ relabel g (relabel f (func _f✝ _ts✝)) = relabel (g ∘ f) (func _f✝ _ts✝)

Next tactic:
simp [ih]
/-- Relabels a term's variables along a bijection. -/
@[simps]
def relabelEquiv (g : α ≃ β) : L.Term α ≃ L.Term β :=
  ⟨relabel g, relabel g.symm, fun t => by 

Proof state:
L : Language
L' : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
γ : Type u_3
g : α ≃ β
t : Term L α
⊢ relabel (⇑g.symm) (relabel (⇑g) t) = t

Next tactic:
simp