l3lab/ntp-mathlib huggingface dataset:
/-- Equivalence of categories is transitive. -/
@[trans, simps, pp_dot]
def trans (e : C ≌ D) (f : D ≌ E) : C ≌ E
    where
  functor := e.functor ⋙ f.functor
  inverse := f.inverse ⋙ e.inverse
  unitIso := by
    refine' Iso.trans e.unitIso _
    exact isoWhiskerLeft e.functor (isoWhiskerRight f.unitIso e.inverse)
  counitIso := by
    refine' Iso.trans _ f.counitIso
    exact isoWhiskerLeft f.inverse (isoWhiskerRight e.counitIso f.functor)
  -- We wouldn't have needed to give this proof if we'd used `Equivalence.mk`,
  -- but we choose to avoid using that here, for the sake of good structure projection `simp`
  -- lemmas.
  functor_unitIso_comp X := by
    dsimp
    rw [← f.functor.map_comp_assoc, e.functor.map_comp, ← counitInv_app_functor, fun_inv_map,
      Iso.inv_hom_id_app_assoc, assoc, Iso.inv_hom_id_app, counit_app_functor, ← Functor.map_comp]
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
f : D ≌ E
X : C
⊢ f.functor.map
      ((f.unitIso.hom.app (e.functor.obj X) ≫ 𝟙 ((𝟭 D).obj (f.inverse.obj (f.functor.obj (e.functor.obj X))))) ≫
        f.unitInv.app (e.functor.obj X)) =
    𝟙 (f.functor.obj (e.functor.obj X))

Next tactic:
erw [comp_id, Iso.hom_inv_id_app, Functor.map_id]
@[simp]
theorem funInvIdAssoc_hom_app (e : C ≌ D) (F : C ⥤ E) (X : C) :
    (funInvIdAssoc e F).hom.app X = F.map (e.unitInv.app X) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : C ⥤ E
X : C
⊢ (funInvIdAssoc e F).hom.app X = F.map (e.unitInv.app X)

Next tactic:
dsimp [funInvIdAssoc]
@[simp]
theorem funInvIdAssoc_hom_app (e : C ≌ D) (F : C ⥤ E) (X : C) :
    (funInvIdAssoc e F).hom.app X = F.map (e.unitInv.app X) := by
  dsimp [funInvIdAssoc]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : C ⥤ E
X : C
⊢ 𝟙 (F.obj (e.inverse.obj (e.functor.obj X))) ≫ F.map (e.unitIso.inv.app X) ≫ 𝟙 (F.obj X) = F.map (e.unitInv.app X)

Next tactic:
aesop_cat
@[simp]
theorem funInvIdAssoc_inv_app (e : C ≌ D) (F : C ⥤ E) (X : C) :
    (funInvIdAssoc e F).inv.app X = F.map (e.unit.app X) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : C ⥤ E
X : C
⊢ (funInvIdAssoc e F).inv.app X = F.map (e.unit.app X)

Next tactic:
dsimp [funInvIdAssoc]
@[simp]
theorem funInvIdAssoc_inv_app (e : C ≌ D) (F : C ⥤ E) (X : C) :
    (funInvIdAssoc e F).inv.app X = F.map (e.unit.app X) := by
  dsimp [funInvIdAssoc]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : C ⥤ E
X : C
⊢ (𝟙 (F.obj X) ≫ F.map (e.unitIso.hom.app X)) ≫ 𝟙 (F.obj (e.inverse.obj (e.functor.obj X))) = F.map (e.unit.app X)

Next tactic:
aesop_cat
@[simp]
theorem invFunIdAssoc_hom_app (e : C ≌ D) (F : D ⥤ E) (X : D) :
    (invFunIdAssoc e F).hom.app X = F.map (e.counit.app X) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : D ⥤ E
X : D
⊢ (invFunIdAssoc e F).hom.app X = F.map (e.counit.app X)

Next tactic:
dsimp [invFunIdAssoc]
@[simp]
theorem invFunIdAssoc_hom_app (e : C ≌ D) (F : D ⥤ E) (X : D) :
    (invFunIdAssoc e F).hom.app X = F.map (e.counit.app X) := by
  dsimp [invFunIdAssoc]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : D ⥤ E
X : D
⊢ 𝟙 (F.obj (e.functor.obj (e.inverse.obj X))) ≫ F.map (e.counitIso.hom.app X) ≫ 𝟙 (F.obj X) = F.map (e.counit.app X)

Next tactic:
aesop_cat
@[simp]
theorem invFunIdAssoc_inv_app (e : C ≌ D) (F : D ⥤ E) (X : D) :
    (invFunIdAssoc e F).inv.app X = F.map (e.counitInv.app X) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : D ⥤ E
X : D
⊢ (invFunIdAssoc e F).inv.app X = F.map (e.counitInv.app X)

Next tactic:
dsimp [invFunIdAssoc]
@[simp]
theorem invFunIdAssoc_inv_app (e : C ≌ D) (F : D ⥤ E) (X : D) :
    (invFunIdAssoc e F).inv.app X = F.map (e.counitInv.app X) := by
  dsimp [invFunIdAssoc]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
F : D ⥤ E
X : D
⊢ (𝟙 (F.obj X) ≫ F.map (e.counitIso.inv.app X)) ≫ 𝟙 (F.obj (e.functor.obj (e.inverse.obj X))) =
    F.map (e.counitInv.app X)

Next tactic:
aesop_cat
@[simp]
theorem cancel_unit_right {X Y : C} (f f' : X ⟶ Y) :
    f ≫ e.unit.app Y = f' ≫ e.unit.app Y ↔ f = f' := by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
X Y : C
f f' : X ⟶ Y
⊢ f ≫ e.unit.app Y = f' ≫ e.unit.app Y ↔ f = f'

Next tactic:
simp only [cancel_mono]
@[simp]
theorem cancel_unitInv_right {X Y : C} (f f' : X ⟶ e.inverse.obj (e.functor.obj Y)) :
    f ≫ e.unitInv.app Y = f' ≫ e.unitInv.app Y ↔ f = f' := by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
X Y : C
f f' : X ⟶ e.inverse.obj (e.functor.obj Y)
⊢ f ≫ e.unitInv.app Y = f' ≫ e.unitInv.app Y ↔ f = f'

Next tactic:
simp only [cancel_mono]
@[simp]
theorem cancel_counit_right {X Y : D} (f f' : X ⟶ e.functor.obj (e.inverse.obj Y)) :
    f ≫ e.counit.app Y = f' ≫ e.counit.app Y ↔ f = f' := by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
X Y : D
f f' : X ⟶ e.functor.obj (e.inverse.obj Y)
⊢ f ≫ e.counit.app Y = f' ≫ e.counit.app Y ↔ f = f'

Next tactic:
simp only [cancel_mono]
@[simp]
theorem cancel_counitInv_right {X Y : D} (f f' : X ⟶ Y) :
    f ≫ e.counitInv.app Y = f' ≫ e.counitInv.app Y ↔ f = f' := by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
X Y : D
f f' : X ⟶ Y
⊢ f ≫ e.counitInv.app Y = f' ≫ e.counitInv.app Y ↔ f = f'

Next tactic:
simp only [cancel_mono]
@[simp]
theorem cancel_unit_right_assoc {W X X' Y : C} (f : W ⟶ X) (g : X ⟶ Y) (f' : W ⟶ X') (g' : X' ⟶ Y) :
    f ≫ g ≫ e.unit.app Y = f' ≫ g' ≫ e.unit.app Y ↔ f ≫ g = f' ≫ g' := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
W X X' Y : C
f : W ⟶ X
g : X ⟶ Y
f' : W ⟶ X'
g' : X' ⟶ Y
⊢ f ≫ g ≫ e.unit.app Y = f' ≫ g' ≫ e.unit.app Y ↔ f ≫ g = f' ≫ g'

Next tactic:
simp only [← Category.assoc, cancel_mono]
@[simp]
theorem cancel_counitInv_right_assoc {W X X' Y : D} (f : W ⟶ X) (g : X ⟶ Y) (f' : W ⟶ X')
    (g' : X' ⟶ Y) : f ≫ g ≫ e.counitInv.app Y = f' ≫ g' ≫ e.counitInv.app Y ↔ f ≫ g = f' ≫ g' := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
W X X' Y : D
f : W ⟶ X
g : X ⟶ Y
f' : W ⟶ X'
g' : X' ⟶ Y
⊢ f ≫ g ≫ e.counitInv.app Y = f' ≫ g' ≫ e.counitInv.app Y ↔ f ≫ g = f' ≫ g'

Next tactic:
simp only [← Category.assoc, cancel_mono]
@[simp]
theorem cancel_unit_right_assoc' {W X X' Y Y' Z : C} (f : W ⟶ X) (g : X ⟶ Y) (h : Y ⟶ Z)
    (f' : W ⟶ X') (g' : X' ⟶ Y') (h' : Y' ⟶ Z) :
    f ≫ g ≫ h ≫ e.unit.app Z = f' ≫ g' ≫ h' ≫ e.unit.app Z ↔ f ≫ g ≫ h = f' ≫ g' ≫ h' := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
W X X' Y Y' Z : C
f : W ⟶ X
g : X ⟶ Y
h : Y ⟶ Z
f' : W ⟶ X'
g' : X' ⟶ Y'
h' : Y' ⟶ Z
⊢ f ≫ g ≫ h ≫ e.unit.app Z = f' ≫ g' ≫ h' ≫ e.unit.app Z ↔ f ≫ g ≫ h = f' ≫ g' ≫ h'

Next tactic:
simp only [← Category.assoc, cancel_mono]
@[simp]
theorem cancel_counitInv_right_assoc' {W X X' Y Y' Z : D} (f : W ⟶ X) (g : X ⟶ Y) (h : Y ⟶ Z)
    (f' : W ⟶ X') (g' : X' ⟶ Y') (h' : Y' ⟶ Z) :
    f ≫ g ≫ h ≫ e.counitInv.app Z = f' ≫ g' ≫ h' ≫ e.counitInv.app Z ↔ f ≫ g ≫ h = f' ≫ g' ≫ h' :=
  by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
E : Type u₃
inst✝ : Category.{v₃, u₃} E
e : C ≌ D
W X X' Y Y' Z : D
f : W ⟶ X
g : X ⟶ Y
h : Y ⟶ Z
f' : W ⟶ X'
g' : X' ⟶ Y'
h' : Y' ⟶ Z
⊢ f ≫ g ≫ h ≫ e.counitInv.app Z = f' ≫ g' ≫ h' ≫ e.counitInv.app Z ↔ f ≫ g ≫ h = f' ≫ g' ≫ h'

Next tactic:
simp only [← Category.assoc, cancel_mono]
@[simp]
theorem functor_asEquivalence (E : C ≌ D) : E.functor.asEquivalence = E := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
E : C ≌ D
⊢ asEquivalence E.functor = E

Next tactic:
cases E
@[simp]
theorem functor_asEquivalence (E : C ≌ D) : E.functor.asEquivalence = E := by
  cases E
  

Proof state:
case mk'
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
functor✝ : C ⥤ D
inverse✝ : D ⥤ C
unitIso✝ : 𝟭 C ≅ functor✝ ⋙ inverse✝
counitIso✝ : inverse✝ ⋙ functor✝ ≅ 𝟭 D
functor_unitIso_comp✝ :
  ∀ (X : C), functor✝.map (unitIso✝.hom.app X) ≫ counitIso✝.hom.app (functor✝.obj X) = 𝟙 (functor✝.obj X)
⊢ asEquivalence (mk' functor✝ inverse✝ unitIso✝ counitIso✝).functor = mk' functor✝ inverse✝ unitIso✝ counitIso✝

Next tactic:
congr
@[simp]
theorem inverse_asEquivalence (E : C ≌ D) : E.inverse.asEquivalence = E.symm := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
E : C ≌ D
⊢ asEquivalence E.inverse = E.symm

Next tactic:
cases E
@[simp]
theorem inverse_asEquivalence (E : C ≌ D) : E.inverse.asEquivalence = E.symm := by
  cases E
  

Proof state:
case mk'
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
functor✝ : C ⥤ D
inverse✝ : D ⥤ C
unitIso✝ : 𝟭 C ≅ functor✝ ⋙ inverse✝
counitIso✝ : inverse✝ ⋙ functor✝ ≅ 𝟭 D
functor_unitIso_comp✝ :
  ∀ (X : C), functor✝.map (unitIso✝.hom.app X) ≫ counitIso✝.hom.app (functor✝.obj X) = 𝟙 (functor✝.obj X)
⊢ asEquivalence (mk' functor✝ inverse✝ unitIso✝ counitIso✝).inverse = (mk' functor✝ inverse✝ unitIso✝ counitIso✝).symm

Next tactic:
congr
@[simp]
theorem fun_inv_map (F : C ⥤ D) [IsEquivalence F] (X Y : D) (f : X ⟶ Y) :
    F.map (F.inv.map f) = F.asEquivalence.counit.app X ≫ f ≫ F.asEquivalence.counitInv.app Y := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝ : IsEquivalence F
X Y : D
f : X ⟶ Y
⊢ F.map ((Functor.inv F).map f) = (asEquivalence F).counit.app X ≫ f ≫ (asEquivalence F).counitInv.app Y

Next tactic:
erw [NatIso.naturality_2]
@[simp]
theorem fun_inv_map (F : C ⥤ D) [IsEquivalence F] (X Y : D) (f : X ⟶ Y) :
    F.map (F.inv.map f) = F.asEquivalence.counit.app X ≫ f ≫ F.asEquivalence.counitInv.app Y := by
  erw [NatIso.naturality_2]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝ : IsEquivalence F
X Y : D
f : X ⟶ Y
⊢ F.map ((Functor.inv F).map f) = ((asEquivalence F).inverse ⋙ (asEquivalence F).functor).map f

Next tactic:
rfl
@[simp]
theorem inv_fun_map (F : C ⥤ D) [IsEquivalence F] (X Y : C) (f : X ⟶ Y) :
    F.inv.map (F.map f) = F.asEquivalence.unitInv.app X ≫ f ≫ F.asEquivalence.unit.app Y := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝ : IsEquivalence F
X Y : C
f : X ⟶ Y
⊢ (Functor.inv F).map (F.map f) = (asEquivalence F).unitInv.app X ≫ f ≫ (asEquivalence F).unit.app Y

Next tactic:
erw [NatIso.naturality_1]
@[simp]
theorem inv_fun_map (F : C ⥤ D) [IsEquivalence F] (X Y : C) (f : X ⟶ Y) :
    F.inv.map (F.map f) = F.asEquivalence.unitInv.app X ≫ f ≫ F.asEquivalence.unit.app Y := by
  erw [NatIso.naturality_1]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝ : IsEquivalence F
X Y : C
f : X ⟶ Y
⊢ (Functor.inv F).map (F.map f) = ((asEquivalence F).functor ⋙ (asEquivalence F).inverse).map f

Next tactic:
rfl
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ G.map ((unitIso ≪≫ hcomp e (Iso.refl (inverse F))).hom.app X) ≫
      (hcomp (Iso.refl (inverse F)) e.symm ≪≫ counitIso).hom.app (G.obj X) =
    𝟙 (G.obj X)

Next tactic:
dsimp [NatIso.hcomp]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ G.map (unitIso.hom.app X ≫ 𝟙 ((inverse F).obj (F.obj X)) ≫ (inverse F).map (e.hom.app X)) ≫
      (e.inv.app ((inverse F).obj (G.obj X)) ≫ F.map (𝟙 ((inverse F).obj (G.obj X)))) ≫ counitIso.hom.app (G.obj X) =
    𝟙 (G.obj X)

Next tactic:
erw [id_comp, F.map_id, comp_id]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ G.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X)) ≫
      e.inv.app ((inverse F).obj (G.obj X)) ≫ counitIso.hom.app (G.obj X) =
    𝟙 (G.obj X)

Next tactic:
apply (cancel_epi (e.hom.app X)).mp
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ e.hom.app X ≫
      G.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X)) ≫
        e.inv.app ((inverse F).obj (G.obj X)) ≫ counitIso.hom.app (G.obj X) =
    e.hom.app X ≫ 𝟙 (G.obj X)

Next tactic:
slice_lhs 1 2 => rw [← e.hom.naturality]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => 

Proof state:
case a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| e.hom.app X ≫ G.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X))
case a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| e.inv.app ((inverse F).obj (G.obj X))
case a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| counitIso.hom.app (G.obj X)

Next tactic:
rw [← e.hom.naturality]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ ((F.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X)) ≫ e.hom.app ((inverse F).obj (G.obj X))) ≫
        e.inv.app ((inverse F).obj (G.obj X))) ≫
      counitIso.hom.app (G.obj X) =
    e.hom.app X ≫ 𝟙 (G.obj X)

Next tactic:
slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => 

Proof state:
case a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| e.hom.app ((inverse F).obj (G.obj X)) ≫ e.inv.app ((inverse F).obj (G.obj X))
case a.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| counitIso.hom.app (G.obj X)
case a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| F.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X))

Next tactic:
rw [← NatTrans.vcomp_app', e.hom_inv_id]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ F.map (unitIso.hom.app X ≫ (inverse F).map (e.hom.app X)) ≫
      (𝟙 F).app ((inverse F).obj (G.obj X)) ≫ counitIso.hom.app (G.obj X) =
    e.hom.app X ≫ 𝟙 (G.obj X)

Next tactic:
simp only [NatTrans.id_app, id_comp, comp_id, F.map_comp, assoc]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
    simp only [NatTrans.id_app, id_comp, comp_id, F.map_comp, assoc]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ F.map (unitIso.hom.app X) ≫ F.map ((inverse F).map (e.hom.app X)) ≫ counitIso.hom.app (G.obj X) = e.hom.app X

Next tactic:
erw [hF.counitIso.hom.naturality]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
    simp only [NatTrans.id_app, id_comp, comp_id, F.map_comp, assoc]
    erw [hF.counitIso.hom.naturality]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ F.map (unitIso.hom.app X) ≫ counitIso.hom.app (F.obj X) ≫ (𝟭 D).map (e.hom.app X) = e.hom.app X

Next tactic:
slice_lhs 1 2 => rw [functor_unitIso_comp]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
    simp only [NatTrans.id_app, id_comp, comp_id, F.map_comp, assoc]
    erw [hF.counitIso.hom.naturality]
    slice_lhs 1 2 => 

Proof state:
case a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| F.map (unitIso.hom.app X) ≫ counitIso.hom.app (F.obj X)
case a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
| (𝟭 D).map (e.hom.app X)

Next tactic:
rw [functor_unitIso_comp]
/-- When a functor `F` is an equivalence of categories, and `G` is isomorphic to `F`, then
`G` is also an equivalence of categories. -/
@[simps!]
def ofIso {F G : C ⥤ D} (e : F ≅ G) (hF : IsEquivalence F) : IsEquivalence G
    where
  inverse := hF.inverse
  unitIso := hF.unitIso ≪≫ NatIso.hcomp e (Iso.refl hF.inverse)
  counitIso := NatIso.hcomp (Iso.refl hF.inverse) e.symm ≪≫ hF.counitIso
  functor_unitIso_comp X := by
    dsimp [NatIso.hcomp]
    erw [id_comp, F.map_id, comp_id]
    apply (cancel_epi (e.hom.app X)).mp
    slice_lhs 1 2 => rw [← e.hom.naturality]
    slice_lhs 2 3 => rw [← NatTrans.vcomp_app', e.hom_inv_id]
    simp only [NatTrans.id_app, id_comp, comp_id, F.map_comp, assoc]
    erw [hF.counitIso.hom.naturality]
    slice_lhs 1 2 => rw [functor_unitIso_comp]
    

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
e : F ≅ G
hF : IsEquivalence F
X : C
⊢ 𝟙 (F.obj X) ≫ (𝟭 D).map (e.hom.app X) = e.hom.app X

Next tactic:
simp only [Functor.id_map, id_comp]