l3lab/ntp-mathlib huggingface dataset:
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G H : C ⥤ D
e : F ≅ G
e' : G ≅ H
hF : IsEquivalence F
⊢ ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF

Next tactic:
dsimp [ofIso]
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  

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

Next tactic:
congr 1
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> 

Proof state:
case e_unitIso
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G H : C ⥤ D
e : F ≅ G
e' : G ≅ H
hF : IsEquivalence F
⊢ (unitIso ≪≫ hcomp e (Iso.refl (inverse F))) ≪≫ hcomp e' (Iso.refl (inverse F)) =
    unitIso ≪≫ hcomp (e ≪≫ e') (Iso.refl (inverse F))

Next tactic:
ext X
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> 

Proof state:
case e_counitIso
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G H : C ⥤ D
e : F ≅ G
e' : G ≅ H
hF : IsEquivalence F
⊢ hcomp (Iso.refl (inverse F)) e'.symm ≪≫ hcomp (Iso.refl (inverse F)) e.symm ≪≫ counitIso =
    hcomp (Iso.refl (inverse F)) (e'.symm ≪≫ e.symm) ≪≫ counitIso

Next tactic:
ext X
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> ext X <;> 

Proof state:
case e_unitIso.w.w.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G H : C ⥤ D
e : F ≅ G
e' : G ≅ H
hF : IsEquivalence F
X : C
⊢ ((unitIso ≪≫ hcomp e (Iso.refl (inverse F))) ≪≫ hcomp e' (Iso.refl (inverse F))).hom.app X =
    (unitIso ≪≫ hcomp (e ≪≫ e') (Iso.refl (inverse F))).hom.app X

Next tactic:
dsimp [NatIso.hcomp]
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> ext X <;> 

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

Next tactic:
dsimp [NatIso.hcomp]
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> ext X <;> dsimp [NatIso.hcomp]
  · 

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

Next tactic:
simp only [id_comp, assoc, Functor.map_comp]
/-- Compatibility of `ofIso` with the composition of isomorphisms of functors -/
theorem ofIso_trans {F G H : C ⥤ D} (e : F ≅ G) (e' : G ≅ H) (hF : IsEquivalence F) :
    ofIso e' (ofIso e hF) = ofIso (e ≪≫ e') hF := by
  dsimp [ofIso]
  congr 1 <;> ext X <;> dsimp [NatIso.hcomp]
  · simp only [id_comp, assoc, Functor.map_comp]
  · 

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

Next tactic:
simp only [Functor.map_id, comp_id, id_comp, assoc]
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
hF : IsEquivalence F
⊢ ofIso (Iso.refl F) hF = hF

Next tactic:
rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  

Proof state:
case mk'
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
⊢ ofIso (Iso.refl F) (mk' Finv Funit Fcounit) = mk' Finv Funit Fcounit

Next tactic:
dsimp [ofIso]
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  

Proof state:
case mk'
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
⊢ mk' Finv (Funit ≪≫ hcomp (Iso.refl F) (Iso.refl Finv)) (hcomp (Iso.refl Finv) (Iso.refl F) ≪≫ Fcounit) =
    mk' Finv Funit Fcounit

Next tactic:
congr 1
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> 

Proof state:
case mk'.e_unitIso
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
⊢ Funit ≪≫ hcomp (Iso.refl F) (Iso.refl Finv) = Funit

Next tactic:
ext X
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> 

Proof state:
case mk'.e_counitIso
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
⊢ hcomp (Iso.refl Finv) (Iso.refl F) ≪≫ Fcounit = Fcounit

Next tactic:
ext X
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> ext X <;> 

Proof state:
case mk'.e_unitIso.w.w.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
X : C
⊢ (Funit ≪≫ hcomp (Iso.refl F) (Iso.refl Finv)).hom.app X = Funit.hom.app X

Next tactic:
dsimp [NatIso.hcomp]
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> ext X <;> 

Proof state:
case mk'.e_counitIso.w.w.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
X : D
⊢ (hcomp (Iso.refl Finv) (Iso.refl F) ≪≫ Fcounit).hom.app X = Fcounit.hom.app X

Next tactic:
dsimp [NatIso.hcomp]
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> ext X <;> dsimp [NatIso.hcomp]
  · 

Proof state:
case mk'.e_unitIso.w.w.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
X : C
⊢ Funit.hom.app X ≫ 𝟙 (Finv.obj (F.obj X)) ≫ Finv.map (𝟙 (F.obj X)) = Funit.hom.app X

Next tactic:
simp only [comp_id, map_id]
/-- Compatibility of `ofIso` with identity isomorphisms of functors -/
theorem ofIso_refl (F : C ⥤ D) (hF : IsEquivalence F) : ofIso (Iso.refl F) hF = hF := by
  rcases hF with ⟨Finv, Funit, Fcounit, Fcomp⟩
  dsimp [ofIso]
  congr 1 <;> ext X <;> dsimp [NatIso.hcomp]
  · simp only [comp_id, map_id]
  · 

Proof state:
case mk'.e_counitIso.w.w.h
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F : C ⥤ D
Finv : D ⥤ C
Funit : 𝟭 C ≅ F ⋙ Finv
Fcounit : Finv ⋙ F ≅ 𝟭 D
Fcomp : ∀ (X : C), F.map (Funit.hom.app X) ≫ Fcounit.hom.app (F.obj X) = 𝟙 (F.obj X)
X : D
⊢ (𝟙 (F.obj (Finv.obj X)) ≫ F.map (𝟙 (Finv.obj X))) ≫ Fcounit.hom.app X = Fcounit.hom.app X

Next tactic:
simp only [id_comp, map_id]
/-- When `F` and `G` are two isomorphic functors, then `F` is an equivalence iff `G` is. -/
@[simps]
def equivOfIso {F G : C ⥤ D} (e : F ≅ G) : IsEquivalence F ≃ IsEquivalence G
    where
  toFun := ofIso e
  invFun := ofIso e.symm
  left_inv hF := 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
⊢ ofIso e.symm (ofIso e hF) = hF

Next tactic:
rw [ofIso_trans, Iso.self_symm_id, ofIso_refl]
/-- When `F` and `G` are two isomorphic functors, then `F` is an equivalence iff `G` is. -/
@[simps]
def equivOfIso {F G : C ⥤ D} (e : F ≅ G) : IsEquivalence F ≃ IsEquivalence G
    where
  toFun := ofIso e
  invFun := ofIso e.symm
  left_inv hF := by rw [ofIso_trans, Iso.self_symm_id, ofIso_refl]
  right_inv hF := 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 G
⊢ ofIso e (ofIso e.symm hF) = hF

Next tactic:
rw [ofIso_trans, Iso.symm_self_id, ofIso_refl]
/-- An equivalence is faithful.

See <https://stacks.math.columbia.edu/tag/02C3>.
-/
instance (priority := 100) faithfulOfEquivalence (F : C ⥤ D) [IsEquivalence F] : Faithful F where
  map_injective := @fun X Y f g h => 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 g : X ⟶ Y
h : F.map f = F.map g
⊢ f = g

Next tactic:
have p : F.inv.map (F.map f) = F.inv.map (F.map g) := congrArg F.inv.map h
/-- An equivalence is faithful.

See <https://stacks.math.columbia.edu/tag/02C3>.
-/
instance (priority := 100) faithfulOfEquivalence (F : C ⥤ D) [IsEquivalence F] : Faithful F where
  map_injective := @fun X Y f g h => by
    have p : F.inv.map (F.map f) = F.inv.map (F.map g) := congrArg F.inv.map h
    

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 g : X ⟶ Y
h : F.map f = F.map g
p : (Functor.inv F).map (F.map f) = (Functor.inv F).map (F.map g)
⊢ f = g

Next tactic:
simpa only [cancel_epi, cancel_mono, IsEquivalence.inv_fun_map] using p
/-- An equivalence is full.

See <https://stacks.math.columbia.edu/tag/02C3>.
-/
instance (priority := 100) fullOfEquivalence (F : C ⥤ D) [IsEquivalence F] : Full F
    where
  preimage {X Y} f := F.asEquivalence.unit.app X ≫ F.inv.map f ≫ F.asEquivalence.unitInv.app Y
  witness {X Y} f :=
    F.inv.map_injective <| 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 : F.obj X ⟶ F.obj Y
⊢ (Functor.inv F).map
      (F.map
        ((fun {X Y} f => (asEquivalence F).unit.app X ≫ (Functor.inv F).map f ≫ (asEquivalence F).unitInv.app Y) f)) =
    (Functor.inv F).map f

Next tactic:
simpa only [IsEquivalence.inv_fun_map, assoc, Iso.inv_hom_id_app_assoc,
        Iso.inv_hom_id_app] using comp_id _
@[simps]
private noncomputable def equivalenceInverse (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] : D ⥤ C
    where
  obj X := F.objPreimage X
  map {X Y} f := F.preimage ((F.objObjPreimageIso X).hom ≫ f ≫ (F.objObjPreimageIso Y).inv)
  map_id X := by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X : D
⊢ { obj := fun X => objPreimage F X,
          map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
      (𝟙 X) =
    𝟙
      ({ obj := fun X => objPreimage F X,
            map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.obj
        X)

Next tactic:
apply F.map_injective
@[simps]
private noncomputable def equivalenceInverse (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] : D ⥤ C
    where
  obj X := F.objPreimage X
  map {X Y} f := F.preimage ((F.objObjPreimageIso X).hom ≫ f ≫ (F.objObjPreimageIso Y).inv)
  map_id X := by apply F.map_injective; 

Proof state:
case a
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X : D
⊢ F.map
      ({ obj := fun X => objPreimage F X,
            map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
        (𝟙 X)) =
    F.map
      (𝟙
        ({ obj := fun X => objPreimage F X,
              map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.obj
          X))

Next tactic:
aesop_cat
@[simps]
private noncomputable def equivalenceInverse (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] : D ⥤ C
    where
  obj X := F.objPreimage X
  map {X Y} f := F.preimage ((F.objObjPreimageIso X).hom ≫ f ≫ (F.objObjPreimageIso Y).inv)
  map_id X := by apply F.map_injective; aesop_cat
  map_comp {X Y Z} f g := by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X Y Z : D
f : X ⟶ Y
g : Y ⟶ Z
⊢ { obj := fun X => objPreimage F X,
          map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
      (f ≫ g) =
    { obj := fun X => objPreimage F X,
            map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
        f ≫
      { obj := fun X => objPreimage F X,
            map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
        g

Next tactic:
apply F.map_injective
@[simps]
private noncomputable def equivalenceInverse (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] : D ⥤ C
    where
  obj X := F.objPreimage X
  map {X Y} f := F.preimage ((F.objObjPreimageIso X).hom ≫ f ≫ (F.objObjPreimageIso Y).inv)
  map_id X := by apply F.map_injective; aesop_cat
  map_comp {X Y Z} f g := by apply F.map_injective; 

Proof state:
case a
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X Y Z : D
f : X ⟶ Y
g : Y ⟶ Z
⊢ F.map
      ({ obj := fun X => objPreimage F X,
            map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
        (f ≫ g)) =
    F.map
      ({ obj := fun X => objPreimage F X,
              map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
          f ≫
        { obj := fun X => objPreimage F X,
              map := fun {X Y} f => F.preimage ((objObjPreimageIso F X).hom ≫ f ≫ (objObjPreimageIso F Y).inv) }.map
          g)

Next tactic:
simp
/-- A functor which is full, faithful, and essentially surjective is an equivalence.

See <https://stacks.math.columbia.edu/tag/02C3>.
-/
noncomputable def ofFullyFaithfullyEssSurj (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] :
    IsEquivalence F :=
  IsEquivalence.mk (equivalenceInverse F)
    (NatIso.ofComponents (fun X => (F.preimageIso <| F.objObjPreimageIso <| F.obj X).symm)
      fun f => by
        

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X✝ Y✝ : C
f : X✝ ⟶ Y✝
⊢ (𝟭 C).map f ≫ ((fun X => (preimageIso F (objObjPreimageIso F (F.obj X))).symm) Y✝).hom =
    ((fun X => (preimageIso F (objObjPreimageIso F (F.obj X))).symm) X✝).hom ≫
      (F ⋙ CategoryTheory.Equivalence.equivalenceInverse F).map f

Next tactic:
apply F.map_injective
/-- A functor which is full, faithful, and essentially surjective is an equivalence.

See <https://stacks.math.columbia.edu/tag/02C3>.
-/
noncomputable def ofFullyFaithfullyEssSurj (F : C ⥤ D) [Full F] [Faithful F] [EssSurj F] :
    IsEquivalence F :=
  IsEquivalence.mk (equivalenceInverse F)
    (NatIso.ofComponents (fun X => (F.preimageIso <| F.objObjPreimageIso <| F.obj X).symm)
      fun f => by
        apply F.map_injective
        

Proof state:
case a
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
F : C ⥤ D
inst✝² : Full F
inst✝¹ : Faithful F
inst✝ : EssSurj F
X✝ Y✝ : C
f : X✝ ⟶ Y✝
⊢ F.map ((𝟭 C).map f ≫ ((fun X => (preimageIso F (objObjPreimageIso F (F.obj X))).symm) Y✝).hom) =
    F.map
      (((fun X => (preimageIso F (objObjPreimageIso F (F.obj X))).symm) X✝).hom ≫
        (F ⋙ CategoryTheory.Equivalence.equivalenceInverse F).map f)

Next tactic:
aesop_cat
instance essSurjInducedFunctor {C' : Type*} (e : C' ≃ D) : EssSurj (inducedFunctor e) where
  mem_essImage Y := ⟨e.symm Y, by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
C' : Type u_1
e : C' ≃ D
Y : D
⊢ Nonempty ((inducedFunctor ⇑e).obj (e.symm Y) ≅ Y)

Next tactic:
simpa using ⟨default⟩
@[simp]
theorem smulAddMonoidHom_apply_of_of [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    {i j} (x : A i) (y : M j) :
    smulAddMonoidHom A M (DirectSum.of A i x) (of M j y) = of M (i +ᵥ j) (GSMul.smul x y) := by
  

Proof state:
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
i : ιA
j : ιB
x : A i
y : M j
⊢ ((smulAddMonoidHom A M) ((of A i) x)) ((of M j) y) = (of M (i +ᵥ j)) (GSMul.smul x y)

Next tactic:
simp [smulAddMonoidHom]
private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    (x : ⨁ i, M i) :
    (1 : ⨁ i, A i) • x = x := by
  

Proof state:
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
x : ⨁ (i : ιB), M i
⊢ 1 • x = x

Next tactic:
suffices smulAddMonoidHom A M 1 = AddMonoidHom.id (⨁ i, M i) from FunLike.congr_fun this x
private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    (x : ⨁ i, M i) :
    (1 : ⨁ i, A i) • x = x := by
  suffices smulAddMonoidHom A M 1 = AddMonoidHom.id (⨁ i, M i) from FunLike.congr_fun this x
  

Proof state:
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
x : ⨁ (i : ιB), M i
⊢ (smulAddMonoidHom A M) 1 = AddMonoidHom.id (⨁ (i : ιB), M i)

Next tactic:
apply DirectSum.addHom_ext
private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    (x : ⨁ i, M i) :
    (1 : ⨁ i, A i) • x = x := by
  suffices smulAddMonoidHom A M 1 = AddMonoidHom.id (⨁ i, M i) from FunLike.congr_fun this x
  apply DirectSum.addHom_ext; 

Proof state:
case H
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
x : ⨁ (i : ιB), M i
⊢ ∀ (i : ιB) (y : M i),
    ((smulAddMonoidHom A M) 1) ((of (fun i => M i) i) y) = (AddMonoidHom.id (⨁ (i : ιB), M i)) ((of (fun i => M i) i) y)

Next tactic:
intro i xi
private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    (x : ⨁ i, M i) :
    (1 : ⨁ i, A i) • x = x := by
  suffices smulAddMonoidHom A M 1 = AddMonoidHom.id (⨁ i, M i) from FunLike.congr_fun this x
  apply DirectSum.addHom_ext; intro i xi
  

Proof state:
case H
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
x : ⨁ (i : ιB), M i
i : ιB
xi : M i
⊢ ((smulAddMonoidHom A M) 1) ((of (fun i => M i) i) xi) = (AddMonoidHom.id (⨁ (i : ιB), M i)) ((of (fun i => M i) i) xi)

Next tactic:
rw [show (1 : DirectSum ιA fun i => A i) = (of A 0) GOne.one by rfl]
private theorem one_smul' [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M]
    (x : ⨁ i, M i) :
    (1 : ⨁ i, A i) • x = x := by
  suffices smulAddMonoidHom A M 1 = AddMonoidHom.id (⨁ i, M i) from FunLike.congr_fun this x
  apply DirectSum.addHom_ext; intro i xi
  rw [show (1 : DirectSum ιA fun i => A i) = (of A 0) GOne.one by 

Proof state:
ιA : Type u_1
ιB : Type u_2
A : ιA → Type u_3
M : ιB → Type u_4
inst✝⁷ : AddMonoid ιA
inst✝⁶ : VAdd ιA ιB
inst✝⁵ : (i : ιA) → AddCommMonoid (A i)
inst✝⁴ : (i : ιB) → AddCommMonoid (M i)
inst✝³ : DecidableEq ιA
inst✝² : DecidableEq ιB
inst✝¹ : GMonoid A
inst✝ : Gmodule A M
x : ⨁ (i : ιB), M i
i : ιB
xi : M i
⊢ 1 = (of A 0) GOne.one

Next tactic:
rfl