lean4-htt/tests/elab/grind_cat.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

653 lines
22 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module
@[expose] public section
universe v v₁ v₂ v₃ u u₁ u₂ u₃
namespace CategoryTheory
section Mathlib.CategoryTheory.Category.Basic
class Category (obj : Type u) : Type max u (v + 1) where
Hom : obj → obj → Type v
/-- The identity morphism on an object. -/
id : ∀ X : obj, Hom X X
/-- Composition of morphisms in a category, written `f ≫ g`. -/
comp : ∀ {X Y Z : obj}, (Hom X Y) → (Hom Y Z) → (Hom X Z)
/-- Identity morphisms are left identities for composition. -/
id_comp : ∀ {X Y : obj} (f : Hom X Y), comp (id X) f = f := by grind
/-- Identity morphisms are right identities for composition. -/
comp_id : ∀ {X Y : obj} (f : Hom X Y), comp f (id Y) = f := by grind
/-- Composition in a category is associative. -/
assoc : ∀ {W X Y Z : obj} (f : Hom W X) (g : Hom X Y) (h : Hom Y Z), comp (comp f g) h = comp f (comp g h) := by grind
infixr:10 " ⟶ " => Category.Hom
scoped notation "𝟙" => Category.id -- type as \b1
scoped infixr:80 " ≫ " => Category.comp
attribute [simp] Category.id_comp Category.comp_id Category.assoc
attribute [grind =] Category.id_comp Category.comp_id
attribute [grind _=_] Category.assoc
end Mathlib.CategoryTheory.Category.Basic
section Mathlib.CategoryTheory.Functor.Basic
structure Functor (C : Type u₁) [Category.{v₁} C] (D : Type u₂) [Category.{v₂} D] : Type max v₁ v₂ u₁ u₂ where
/-- The action of a functor on objects. -/
obj : C → D
/-- The action of a functor on morphisms. -/
map : ∀ {X Y : C}, (X ⟶ Y) → ((obj X) ⟶ (obj Y))
/-- A functor preserves identity morphisms. -/
map_id : ∀ X : C, map (𝟙 X) = 𝟙 (obj X) := by grind
/-- A functor preserves composition. -/
map_comp : ∀ {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z), map (f ≫ g) = (map f) ≫ (map g) := by grind
scoped infixr:26 " ⥤ " => Functor
attribute [simp] Functor.map_id Functor.map_comp
attribute [grind =] Functor.map_id
attribute [grind _=_] Functor.map_comp
variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] {E : Type u₃} [Category.{v₃} E]
variable {F G H : Functor C D}
namespace Functor
def comp (F : Functor C D) (G : Functor D E) : Functor C E where
obj X := G.obj (F.obj X)
map f := G.map (F.map f)
-- Note `map_id` and `map_comp` are handled by `grind`.
infixr:80 " ⋙ " => Functor.comp
variable {X Y : C} {G : Functor D E}
@[simp, grind =] theorem comp_obj : (F.comp G).obj X = G.obj (F.obj X) := rfl
@[simp, grind =] theorem comp_map (f : X ⟶ Y) : (F.comp G).map f = G.map (F.map f) := rfl
end Functor
end Mathlib.CategoryTheory.Functor.Basic
variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] {E : Type u₃} [Category.{v₃} E] {E' : Type u₄} [Category.{v₄} E']
variable {F G H : Functor C D}
section Mathlib.CategoryTheory.NatTrans
@[ext]
structure NatTrans [Category.{v₁, u₁} C] [Category.{v₂, u₂} D] (F G : Functor C D) : Type max u₁ v₂ where
/-- The component of a natural transformation. -/
app : ∀ X : C, F.obj X ⟶ G.obj X
/-- The naturality square for a given morphism. -/
naturality : ∀ ⦃X Y : C⦄ (f : X ⟶ Y), F.map f ≫ app Y = app X ≫ G.map f := by grind
-- In the following examples `[grind ext] NatTrans.ext` is more effective than
-- `[grind ext] NatTrans` which only applies eta-extension because it will allows
-- chaining with function extensionality
attribute [grind ext] NatTrans.ext
attribute [simp, grind _=_] NatTrans.naturality
namespace NatTrans
variable {X : C}
protected def id (F : Functor C D) : NatTrans F F where app X := 𝟙 (F.obj X)
@[simp, grind =] theorem id_app' : (NatTrans.id F).app X = 𝟙 (F.obj X) := rfl
protected def vcomp (α : NatTrans F G) (β : NatTrans G H) : NatTrans F H where
app X := α.app X ≫ β.app X
-- `naturality` is now handled by `grind`; in Mathlib this relies on `@[reassoc]` attributes.
-- Manual proof:
-- rw [← Category.assoc]
-- rw [α.naturality f]
-- rw [Category.assoc]
-- rw [β.naturality f]
-- rw [← Category.assoc]
@[simp, grind =] theorem vcomp_app (α : NatTrans F G) (β : NatTrans G H) (X : C) :
(α.vcomp β).app X = α.app X ≫ β.app X := rfl
end NatTrans
end Mathlib.CategoryTheory.NatTrans
section Mathlib.CategoryTheory.Iso
structure Iso {C : Type u} [Category.{v} C] (X Y : C) where
hom : X ⟶ Y
inv : Y ⟶ X
hom_inv_id : hom ≫ inv = 𝟙 X := by grind
inv_hom_id : inv ≫ hom = 𝟙 Y := by grind
attribute [simp, grind =] Iso.hom_inv_id Iso.inv_hom_id
/-- Notation for an isomorphism in a category. -/
infixr:10 " ≅ " => Iso -- type as \cong or \iso
variable {C : Type u} [Category.{v} C] {X Y Z : C}
namespace Iso
@[ext, grind ext]
theorem ext ⦃α β : X ≅ Y⦄ (w : α.hom = β.hom) : α = β :=
suffices α.inv = β.inv by grind [Iso]
calc
α.inv = α.inv ≫ β.hom ≫ β.inv := by grind
_ = β.inv := by grind
/-- Inverse isomorphism. -/
@[symm]
def symm (I : X ≅ Y) : Y ≅ X where
hom := I.inv
inv := I.hom
@[simp, grind =]
theorem symm_hom (α : X ≅ Y) : α.symm.hom = α.inv :=
rfl
@[simp, grind =]
theorem symm_inv (α : X ≅ Y) : α.symm.inv = α.hom :=
rfl
@[simp, grind =]
theorem symm_mk {X Y : C} (hom : X ⟶ Y) (inv : Y ⟶ X) (hom_inv_id) (inv_hom_id) :
Iso.symm { hom, inv, hom_inv_id := hom_inv_id, inv_hom_id := inv_hom_id } =
{ hom := inv, inv := hom, hom_inv_id := inv_hom_id, inv_hom_id := hom_inv_id } :=
rfl
@[simp, grind =]
theorem symm_symm_eq {X Y : C} (α : X ≅ Y) : α.symm.symm = α := rfl
/-- Identity isomorphism. -/
@[refl]
def refl (X : C) : X ≅ X where
hom := 𝟙 X
inv := 𝟙 X
@[simp, grind =]
theorem refl_hom (X : C) : (Iso.refl X).hom = 𝟙 X := rfl
@[simp, grind =]
theorem refl_inv (X : C) : (Iso.refl X).inv = 𝟙 X := rfl
instance : Inhabited (X ≅ X) := ⟨Iso.refl X⟩
/-- Composition of two isomorphisms -/
def trans (α : X ≅ Y) (β : Y ≅ Z) : X ≅ Z where
hom := α.hom ≫ β.hom
inv := β.inv ≫ α.inv
/-- Notation for composition of isomorphisms. -/
infixr:80 " ≪≫ " => Iso.trans
@[grind =] theorem trans_hom (α : X ≅ Y) (β : Y ≅ Z) : (α ≪≫ β).hom = α.hom ≫ β.hom := rfl
@[grind =] theorem trans_inv (α : X ≅ Y) (β : Y ≅ Z) : (α ≪≫ β).inv = β.inv ≫ α.inv := rfl
instance instTransIso : Trans (α := C) (· ≅ ·) (· ≅ ·) (· ≅ ·) where
trans := trans
/-- `LeftInverse g f` means that g is a left inverse to f. That is, `g ∘ f = id`. -/
def Function.LeftInverse (g : β → α) (f : α → β) : Prop :=
∀ x, g (f x) = x
/-- `RightInverse g f` means that g is a right inverse to f. That is, `f ∘ g = id`. -/
def Function.RightInverse (g : β → α) (f : α → β) : Prop :=
LeftInverse f g
open Function
/-- `α ≃ β` is the type of functions from `α → β` with a two-sided inverse. -/
structure Equiv (α : Sort _) (β : Sort _) where
protected toFun : α → β
protected invFun : β → α
protected left_inv : LeftInverse invFun toFun := by grind
protected right_inv : RightInverse invFun toFun := by grind
@[inherit_doc]
infixl:25 " ≃ " => Equiv
attribute [local grind] Function.LeftInverse Function.RightInverse in
/-- The bijection `(Z ⟶ X) ≃ (Z ⟶ Y)` induced by `α : X ≅ Y`. -/
def homToEquiv (α : X ≅ Y) {Z : C} : (Z ⟶ X) ≃ (Z ⟶ Y) where
toFun f := f ≫ α.hom
invFun g := g ≫ α.inv
end Iso
/-- `IsIso` typeclass expressing that a morphism is invertible. -/
class IsIso (f : X ⟶ Y) : Prop where
/-- The existence of an inverse morphism. -/
out : ∃ inv : Y ⟶ X, f ≫ inv = 𝟙 X ∧ inv ≫ f = 𝟙 Y
/-- The inverse of a morphism `f` when we have `[IsIso f]`.
-/
noncomputable def inv (f : X ⟶ Y) [I : IsIso f] : Y ⟶ X :=
Classical.choose I.1
namespace IsIso
@[simp, grind =]
theorem hom_inv_id (f : X ⟶ Y) [I : IsIso f] : f ≫ inv f = 𝟙 X :=
(Classical.choose_spec I.1).left
@[simp, grind =]
theorem inv_hom_id (f : X ⟶ Y) [I : IsIso f] : inv f ≫ f = 𝟙 Y :=
(Classical.choose_spec I.1).right
end IsIso
theorem Iso.isIso_hom (e : X ≅ Y) : IsIso e.hom :=
⟨e.inv, by simp, by simp⟩
theorem Iso.isIso_inv (e : X ≅ Y) : IsIso e.inv :=
⟨e.hom, by simp, by simp⟩
attribute [instance] Iso.isIso_hom Iso.isIso_inv
open IsIso
/-- Reinterpret a morphism `f` with an `IsIso f` instance as an `Iso`. -/
noncomputable def asIso (f : X ⟶ Y) [IsIso f] : X ≅ Y :=
⟨f, inv f, hom_inv_id f, inv_hom_id f⟩
@[simp, grind =]
theorem asIso_hom (f : X ⟶ Y) {_ : IsIso f} : (asIso f).hom = f :=
rfl
@[simp, grind =]
theorem asIso_inv (f : X ⟶ Y) {_ : IsIso f} : (asIso f).inv = inv f :=
rfl
namespace IsIso
@[grind ←=]
theorem inv_eq_of_hom_inv_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (hom_inv_id : f ≫ g = 𝟙 X) :
inv f = g := by
have := congrArg (inv f ≫ ·) hom_inv_id
grind
theorem inv_eq_of_inv_hom_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (inv_hom_id : g ≫ f = 𝟙 Y) :
inv f = g := by
have := congrArg (· ≫ inv f) inv_hom_id
grind
theorem eq_inv_of_hom_inv_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (hom_inv_id : f ≫ g = 𝟙 X) :
g = inv f :=
(inv_eq_of_hom_inv_id hom_inv_id).symm
theorem eq_inv_of_inv_hom_id {f : X ⟶ Y} [IsIso f] {g : Y ⟶ X} (inv_hom_id : g ≫ f = 𝟙 Y) :
g = inv f :=
(inv_eq_of_inv_hom_id inv_hom_id).symm
instance inv_isIso {f : X ⟶ Y} [IsIso f] : IsIso (inv f) :=
{ out := ⟨f, by simp, by simp⟩ }
end IsIso
namespace Iso
variable (e : X ≅ Y)
@[grind =]
theorem map_hom_inv_id (F : C ⥤ D) :
F.map e.hom ≫ F.map e.inv = 𝟙 _ := by grind
@[grind =]
theorem map_inv_hom_id (F : C ⥤ D) :
F.map e.inv ≫ F.map e.hom = 𝟙 _ := by grind
end Iso
namespace Functor
variable {D : Type u₂}
variable [Category.{v₂} D]
/-- A functor `F : C ⥤ D` sends isomorphisms `i : X ≅ Y` to isomorphisms `F.obj X ≅ F.obj Y` -/
def mapIso (F : C ⥤ D) {X Y : C} (i : X ≅ Y) : F.obj X ≅ F.obj Y where
hom := F.map i.hom
inv := F.map i.inv
@[simp, grind =]
theorem mapIso_hom (F : C ⥤ D) {X Y : C} (i : X ≅ Y) : (F.mapIso i).hom = F.map i.hom := rfl
@[simp, grind =]
theorem mapIso_inv (F : C ⥤ D) {X Y : C} (i : X ≅ Y) : (F.mapIso i).inv = F.map i.inv := rfl
@[simp]
theorem mapIso_symm (F : C ⥤ D) {X Y : C} (i : X ≅ Y) : F.mapIso i.symm = (F.mapIso i).symm :=
rfl
@[simp]
theorem mapIso_trans (F : C ⥤ D) {X Y Z : C} (i : X ≅ Y) (j : Y ≅ Z) :
F.mapIso (i ≪≫ j) = F.mapIso i ≪≫ F.mapIso j := by
ext; apply Functor.map_comp
@[simp]
theorem mapIso_refl (F : C ⥤ D) (X : C) : F.mapIso (Iso.refl X) = Iso.refl (F.obj X) :=
Iso.ext <| F.map_id X
instance map_isIso (F : C ⥤ D) (f : X ⟶ Y) [IsIso f] : IsIso (F.map f) :=
(F.mapIso (asIso f)).isIso_hom
@[simp]
theorem map_inv (F : C ⥤ D) {X Y : C} (f : X ⟶ Y) [IsIso f] : F.map (inv f) = inv (F.map f) := by
apply eq_inv_of_hom_inv_id
simp [← F.map_comp]
theorem map_hom_inv (F : C ⥤ D) {X Y : C} (f : X ⟶ Y) [IsIso f] :
F.map f ≫ F.map (inv f) = 𝟙 (F.obj X) := by simp
theorem map_inv_hom (F : C ⥤ D) {X Y : C} (f : X ⟶ Y) [IsIso f] :
F.map (inv f) ≫ F.map f = 𝟙 (F.obj Y) := by simp
end Functor
end Mathlib.CategoryTheory.Iso
section Mathlib.CategoryTheory.Functor.Category
instance Functor.category : Category.{max u₁ v₂} (Functor C D) where
Hom F G := NatTrans F G
id F := NatTrans.id F
comp α β := NatTrans.vcomp α β
-- Here we're okay: all the proofs are handled by `grind`.
namespace NatTrans
@[ext, grind ext]
theorem ext' {α β : F ⟶ G} (w : α.app = β.app) : α = β := NatTrans.ext w
@[simp, grind =]
theorem id_app (F : Functor C D) (X : C) : (𝟙 F : F ⟶ F).app X = 𝟙 (F.obj X) := rfl
@[simp, grind _=_]
theorem comp_app {F G H : Functor C D} (α : F ⟶ G) (β : G ⟶ H) (X : C) :
(α ≫ β).app X = α.app X ≫ β.app X := rfl
theorem app_naturality {F G : Functor C (Functor D E)} (T : F ⟶ G) (X : C) {Y Z : D} (f : Y ⟶ Z) :
(F.obj X).map f ≫ (T.app X).app Z = (T.app X).app Y ≫ (G.obj X).map f := by
grind
theorem naturality_app {F G : Functor C (Functor D E)} (T : F ⟶ G) (Z : D) {X Y : C} (f : X ⟶ Y) :
(F.map f).app Z ≫ (T.app Y).app Z = (T.app X).app Z ≫ (G.map f).app Z := by
grind -- this is done manually in Mathlib!
-- rw [← comp_app]
-- rw [T.naturality f]
-- rw [comp_app]
@[simp]
theorem vcomp_eq_comp (α : F ⟶ G) (β : G ⟶ H) : NatTrans.vcomp α β = α ≫ β := rfl
theorem vcomp_app' (α : F ⟶ G) (β : G ⟶ H) (X : C) : (α ≫ β).app X = α.app X ≫ β.app X := rfl
theorem congr_app {α β : F ⟶ G} (h : α = β) (X : C) : α.app X = β.app X := by grind
open Category Functor NatTrans
def hcomp {H I : Functor D E} (α : F ⟶ G) (β : H ⟶ I) : F.comp H ⟶ G.comp I where
app := fun X : C => β.app (F.obj X) ≫ I.map (α.app X)
-- `grind` can now handle `naturality`, while Mathlib does this manually:
-- rw [Functor.comp_map, Functor.comp_map, ← assoc, naturality, assoc, ← I.map_comp, naturality,
-- map_comp, assoc]
/-- Notation for horizontal composition of natural transformations. -/
infixl:80 " ◫ " => hcomp
@[simp] theorem hcomp_app {H I : Functor D E} (α : F ⟶ G) (β : H ⟶ I) (X : C) :
(α ◫ β).app X = β.app (F.obj X) ≫ I.map (α.app X) := rfl
attribute [grind =] hcomp_app
theorem hcomp_id_app {H : D ⥤ E} (α : F ⟶ G) (X : C) : (α𝟙 H).app X = H.map (α.app X) := by
grind
theorem id_hcomp_app {H : E ⥤ C} (α : F ⟶ G) (X : E) : (𝟙 H ◫ α).app X = α.app _ := by
grind
-- Note that we don't yet prove a `hcomp_assoc` lemma here: even stating it is painful, because we
-- need to use associativity of functor composition. (It's true without the explicit associator,
-- because functor composition is definitionally associative,
-- but relying on the definitional equality causes bad problems with elaboration later.)
theorem exchange {I J K : D ⥤ E} (α : F ⟶ G) (β : G ⟶ H) (γ : I ⟶ J) (δ : J ⟶ K) :
(α ≫ β) ◫ (γ ≫ δ) = (αγ) ≫ β ◫ δ := by
grind
theorem naturality_app_app {F G : C ⥤ D ⥤ E ⥤ E'}
(α : F ⟶ G) {X₁ Y₁ : C} (f : X₁ ⟶ Y₁) (X₂ : D) (X₃ : E) :
((F.map f).app X₂).app X₃ ≫ ((α.app Y₁).app X₂).app X₃ =
((α.app X₁).app X₂).app X₃ ≫ ((G.map f).app X₂).app X₃ := by
grind
end NatTrans
namespace Functor
/-- Flip the arguments of a bifunctor. See also `Currying.lean`. -/
protected def flip (F : C ⥤ D ⥤ E) : D ⥤ C ⥤ E where
obj k :=
{ obj := fun j => (F.obj j).obj k,
map := fun f => (F.map f).app k, }
map f := { app := fun j => (F.obj j).map f }
@[simp] theorem flip_obj_obj (F : C ⥤ D ⥤ E) (k : D) : (F.flip.obj k).obj = fun j => (F.obj j).obj k := rfl
@[simp] theorem flip_obj_map (F : C ⥤ D ⥤ E) (k : D) {X Y : C}(f : X ⟶ Y) : (F.flip.obj k).map f = (F.map f).app k := rfl
@[simp] theorem flip_map_app (F : C ⥤ D ⥤ E) {X Y : D} (f : X ⟶ Y) (k : C) : (F.flip.map f).app k = (F.obj k).map f := rfl
attribute [grind =] flip_obj_obj flip_obj_map flip_map_app
end Functor
variable (C D E) in
/-- The functor `(C ⥤ D ⥤ E) ⥤ D ⥤ C ⥤ E` which flips the variables. -/
def flipFunctor : (C ⥤ D ⥤ E) ⥤ D ⥤ C ⥤ E where
obj F := F.flip
map {F₁ F₂} φ := { app := fun Y => { app := fun X => (φ.app X).app Y } }
namespace Iso
@[simp]
theorem map_hom_inv_id_app {X Y : C} (e : X ≅ Y) (F : C ⥤ D ⥤ E) (Z : D) :
(F.map e.hom).app Z ≫ (F.map e.inv).app Z = 𝟙 _ := by
grind
@[simp]
theorem map_inv_hom_id_app {X Y : C} (e : X ≅ Y) (F : C ⥤ D ⥤ E) (Z : D) :
(F.map e.inv).app Z ≫ (F.map e.hom).app Z = 𝟙 _ := by
grind
end Iso
end Mathlib.CategoryTheory.Functor.Category
section Mathlib.CategoryTheory.NatIso
open NatTrans
variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] {E : Type u₃}
[Category.{v₃} E] {E' : Type u₄} [Category.{v₄} E']
namespace Iso
/-- The application of a natural isomorphism to an object. We put this definition in a different
namespace, so that we can use `α.app` -/
def app {F G : C ⥤ D} (α : F ≅ G) (X : C) :
F.obj X ≅ G.obj X where
hom := α.hom.app X
inv := α.inv.app X
hom_inv_id := by rw [← comp_app, Iso.hom_inv_id]; rfl
inv_hom_id := by rw [← comp_app, Iso.inv_hom_id]; rfl
@[simp, grind =] theorem app_hom {F G : C ⥤ D} (α : F ≅ G) (X : C) : (α.app X).hom = α.hom.app X := rfl
@[simp, grind =] theorem app_inv {F G : C ⥤ D} (α : F ≅ G) (X : C) : (α.app X).inv = α.inv.app X := rfl
@[simp, grind =]
theorem hom_inv_id_app {F G : C ⥤ D} (α : F ≅ G) (X : C) :
α.hom.app X ≫ α.inv.app X = 𝟙 (F.obj X) :=
congrFun (congrArg NatTrans.app α.hom_inv_id) X
@[simp, grind =]
theorem inv_hom_id_app {F G : C ⥤ D} (α : F ≅ G) (X : C) :
α.inv.app X ≫ α.hom.app X = 𝟙 (G.obj X) :=
congrFun (congrArg NatTrans.app α.inv_hom_id) X
@[simp]
theorem hom_inv_id_app_app {F G : C ⥤ D ⥤ E} (e : F ≅ G) (X₁ : C) (X₂ : D) :
(e.hom.app X₁).app X₂ ≫ (e.inv.app X₁).app X₂ = 𝟙 _ := by
rw [← NatTrans.comp_app, Iso.hom_inv_id_app, NatTrans.id_app]
@[simp]
theorem inv_hom_id_app_app {F G : C ⥤ D ⥤ E} (e : F ≅ G) (X₁ : C) (X₂ : D) :
(e.inv.app X₁).app X₂ ≫ (e.hom.app X₁).app X₂ = 𝟙 _ := by
rw [← NatTrans.comp_app, Iso.inv_hom_id_app, NatTrans.id_app]
@[simp]
theorem hom_inv_id_app_app_app {F G : C ⥤ D ⥤ E ⥤ E'} (e : F ≅ G)
(X₁ : C) (X₂ : D) (X₃ : E) :
((e.hom.app X₁).app X₂).app X₃ ≫ ((e.inv.app X₁).app X₂).app X₃ = 𝟙 _ := by
rw [← NatTrans.comp_app, ← NatTrans.comp_app, Iso.hom_inv_id_app,
NatTrans.id_app, NatTrans.id_app]
@[simp]
theorem inv_hom_id_app_app_app {F G : C ⥤ D ⥤ E ⥤ E'} (e : F ≅ G)
(X₁ : C) (X₂ : D) (X₃ : E) :
((e.inv.app X₁).app X₂).app X₃ ≫ ((e.hom.app X₁).app X₂).app X₃ = 𝟙 _ := by
rw [← NatTrans.comp_app, ← NatTrans.comp_app, Iso.inv_hom_id_app,
NatTrans.id_app, NatTrans.id_app]
end Iso
namespace NatIso
open CategoryTheory.Category CategoryTheory.Functor
@[simp]
theorem trans_app {F G H : C ⥤ D} (α : F ≅ G) (β : G ≅ H) (X : C) :
(α ≪≫ β).app X = α.app X ≪≫ β.app X :=
rfl
variable {F G : C ⥤ D}
instance hom_app_isIso (α : F ≅ G) (X : C) : IsIso (α.hom.app X) :=
⟨⟨α.inv.app X, ⟨by grind, by grind⟩⟩⟩
instance inv_app_isIso (α : F ≅ G) (X : C) : IsIso (α.inv.app X) :=
⟨⟨α.hom.app X, ⟨by grind, by grind⟩⟩⟩
section
variable (α : F ≅ G)
@[simp]
theorem inv_inv_app {F G : C ⥤ D} (e : F ≅ G) (X : C) : inv (e.inv.app X) = e.hom.app X := by
grind
end
variable {X Y : C}
theorem naturality_1 (α : F ≅ G) (f : X ⟶ Y) : α.inv.app X ≫ F.map f ≫ α.hom.app Y = G.map f := by
grind
theorem naturality_2 (α : F ≅ G) (f : X ⟶ Y) : α.hom.app X ≫ G.map f ≫ α.inv.app Y = F.map f := by
grind
theorem naturality_1' (α : F ⟶ G) (f : X ⟶ Y) {_ : IsIso (α.app X)} :
inv (α.app X) ≫ F.map f ≫ α.app Y = G.map f := by grind
@[simp]
theorem naturality_2' (α : F ⟶ G) (f : X ⟶ Y) {_ : IsIso (α.app Y)} :
α.app X ≫ G.map f ≫ inv (α.app Y) = F.map f := by
grind
/-- The components of a natural isomorphism are isomorphisms.
-/
instance isIso_app_of_isIso (α : F ⟶ G) [IsIso α] (X) : IsIso (α.app X) :=
⟨⟨(inv α).app X, ⟨by grind, by grind⟩⟩⟩
@[simp]
theorem isIso_inv_app (α : F ⟶ G) {_ : IsIso α} (X) : (inv α).app X = inv (α.app X) := by
grind
@[simp]
theorem inv_map_inv_app (F : C ⥤ D ⥤ E) {X Y : C} (e : X ≅ Y) (Z : D) :
inv ((F.map e.inv).app Z) = (F.map e.hom).app Z := by
grind
/-- Construct a natural isomorphism between functors by giving object level isomorphisms,
and checking naturality only in the forward direction.
-/
def ofComponents (app : ∀ X : C, F.obj X ≅ G.obj X)
(naturality : ∀ {X Y : C} (f : X ⟶ Y),
F.map f ≫ (app Y).hom = (app X).hom ≫ G.map f := by grind) :
F ≅ G where
hom := { app := fun X => (app X).hom }
inv :=
{ app := fun X => (app X).inv,
naturality := fun X Y f => by
have h := congrArg (fun f => (app X).inv ≫ f ≫ (app Y).inv) (naturality f).symm
grind }
hom_inv_id := by
grind
inv_hom_id := by
grind
@[simp, grind =]
theorem ofComponents_hom_app (app : ∀ X : C, F.obj X ≅ G.obj X) (naturality) (X : C) :
(ofComponents app naturality).hom.app X = (app X).hom := rfl
@[simp, grind =]
theorem ofComponents_inv_app (app : ∀ X : C, F.obj X ≅ G.obj X) (naturality) (X : C) :
(ofComponents app naturality).inv.app X = (app X).inv := rfl
theorem ofComponents_app (app : ∀ X : C, F.obj X ≅ G.obj X) (naturality) (X : C) :
(ofComponents app naturality).app X = app X := by
grind
@[simp]
theorem ofComponents.app (app : ∀ X : C, F.obj X ≅ G.obj X) (naturality) (X) :
(ofComponents app naturality).app X = app X := by grind
-- Making this an instance would cause a typeclass inference loop with `isIso_app_of_isIso`.
/-- A natural transformation is an isomorphism if all its components are isomorphisms.
-/
theorem isIso_of_isIso_app (α : F ⟶ G) [∀ X : C, IsIso (α.app X)] : IsIso α :=
(ofComponents (fun X => asIso (α.app X)) (by simp)).isIso_hom
/-- Horizontal composition of natural isomorphisms. -/
def hcomp {F G : C ⥤ D} {H I : D ⥤ E} (α : F ≅ G) (β : H ≅ I) : F ⋙ H ≅ G ⋙ I := by
refine ⟨α.hom ◫ β.hom, α.inv ◫ β.inv, ?_, ?_⟩
· ext
rw [← NatTrans.exchange]
simp
· ext
rw [← NatTrans.exchange]
simp
@[simp]
theorem hcomp_hom {F G : C ⥤ D} {H I : D ⥤ E} (α : F ≅ G) (β : H ≅ I) :
(hcomp α β).hom = α.hom ◫ β.hom := rfl
@[simp]
theorem hcomp_inv {F G : C ⥤ D} {H I : D ⥤ E} (α : F ≅ G) (β : H ≅ I) :
(hcomp α β).inv = α.inv ◫ β.inv := rfl
theorem isIso_map_iff {F₁ F₂ : C ⥤ D} (e : F₁ ≅ F₂) {X Y : C} (f : X ⟶ Y) :
IsIso (F₁.map f) ↔ IsIso (F₂.map f) := by
revert F₁ F₂
suffices ∀ {F₁ F₂ : C ⥤ D} (_ : F₁ ≅ F₂) (_ : IsIso (F₁.map f)), IsIso (F₂.map f) by
exact fun F₁ F₂ e => ⟨this e, this e.symm⟩
intro F₁ F₂ e hf
refine IsIso.mk ⟨e.inv.app Y ≫ inv (F₁.map f) ≫ e.hom.app X, ?_, ?_⟩
· grind (ematch := 6)
· grind (ematch := 7)
end NatIso
theorem NatTrans.isIso_iff_isIso_app {F G : C ⥤ D} (τ : F ⟶ G) :
IsIso τ ↔ ∀ X, IsIso (τ.app X) :=
⟨fun _ ↦ inferInstance, fun _ ↦ NatIso.isIso_of_isIso_app _⟩
end Mathlib.CategoryTheory.NatIso
end CategoryTheory