Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
Project: Xena
Views: 18536License: APACHE
/- Copyright (c) 2017 Scott Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Stephen Morgan, Scott Morrison, Floris van Doorn -/ import category_theory.const import category_theory.yoneda import category_theory.concrete_category.bundled_hom import category_theory.equivalence universes v u u' -- declare the `v`'s first; see `category_theory.category` for an explanation open category_theory -- There is an awkward difficulty with universes here. -- If we allowed `J` to be a small category in `Prop`, we'd run into trouble -- because `yoneda.obj (F : (J ⥤ C)ᵒᵖ)` will be a functor into `Sort (max v 1)`, -- not into `Sort v`. -- So we don't allow this case; it's not particularly useful anyway. variables {J : Type v} [small_category J] variables {C : Type u} [𝒞 : category.{v} C] include 𝒞 open category_theory open category_theory.category open category_theory.functor open opposite namespace category_theory namespace functor variables {J C} (F : J ⥤ C) /-- `F.cones` is the functor assigning to an object `X` the type of natural transformations from the constant functor with value `X` to `F`. An object representing this functor is a limit of `F`. -/ def cones : Cᵒᵖ ⥤ Type v := (const J).op ⋙ (yoneda.obj F) lemma cones_obj (X : Cᵒᵖ) : F.cones.obj X = ((const J).obj (unop X) ⟶ F) := rfl @[simp] lemma cones_map_app {X₁ X₂ : Cᵒᵖ} (f : X₁ ⟶ X₂) (t : F.cones.obj X₁) (j : J) : (F.cones.map f t).app j = f.unop ≫ t.app j := rfl /-- `F.cocones` is the functor assigning to an object `X` the type of natural transformations from `F` to the constant functor with value `X`. An object corepresenting this functor is a colimit of `F`. -/ def cocones : C ⥤ Type v := const J ⋙ coyoneda.obj (op F) lemma cocones_obj (X : C) : F.cocones.obj X = (F ⟶ (const J).obj X) := rfl @[simp] lemma cocones_map_app {X₁ X₂ : C} (f : X₁ ⟶ X₂) (t : F.cocones.obj X₁) (j : J) : (F.cocones.map f t).app j = t.app j ≫ f := rfl end functor section variables (J C) /-- Functorially associated to each functor `J ⥤ C`, we have the `C`-presheaf consisting of cones with a given cone point. -/ @[simps] def cones : (J ⥤ C) ⥤ (Cᵒᵖ ⥤ Type v) := { obj := functor.cones, map := λ F G f, whisker_left (const J).op (yoneda.map f) } /-- Contravariantly associated to each functor `J ⥤ C`, we have the `C`-copresheaf consisting of cocones with a given cocone point. -/ @[simps] def cocones : (J ⥤ C)ᵒᵖ ⥤ (C ⥤ Type v) := { obj := λ F, functor.cocones (unop F), map := λ F G f, whisker_left (const J) (coyoneda.map f) } end namespace limits /-- A `c : cone F` is: * an object `c.X` and * a natural transformation `c.π : c.X ⟶ F` from the constant `c.X` functor to `F`. `cone F` is equivalent, via `cone.equiv` below, to `Σ X, F.cones.obj X`. -/ structure cone (F : J ⥤ C) := (X : C) (π : (const J).obj X ⟶ F) @[simp] lemma cone.w {F : J ⥤ C} (c : cone F) {j j' : J} (f : j ⟶ j') : c.π.app j ≫ F.map f = c.π.app j' := by convert ←(c.π.naturality f).symm; apply id_comp /-- A `c : cocone F` is * an object `c.X` and * a natural transformation `c.ι : F ⟶ c.X` from `F` to the constant `c.X` functor. `cocone F` is equivalent, via `cone.equiv` below, to `Σ X, F.cocones.obj X`. -/ structure cocone (F : J ⥤ C) := (X : C) (ι : F ⟶ (const J).obj X) @[simp] lemma cocone.w {F : J ⥤ C} (c : cocone F) {j j' : J} (f : j ⟶ j') : F.map f ≫ c.ι.app j' = c.ι.app j := by convert ←(c.ι.naturality f); apply comp_id variables {F : J ⥤ C} namespace cone def equiv (F : J ⥤ C) : cone F ≅ Σ X, F.cones.obj X := { hom := λ c, ⟨op c.X, c.π⟩, inv := λ c, { X := unop c.1, π := c.2 }, hom_inv_id' := begin ext, cases x, refl, end, inv_hom_id' := begin ext, cases x, refl, end } @[simp] def extensions (c : cone F) : yoneda.obj c.X ⟶ F.cones := { app := λ X f, ((const J).map f) ≫ c.π } /-- A map to the vertex of a cone induces a cone by composition. -/ @[simp] def extend (c : cone F) {X : C} (f : X ⟶ c.X) : cone F := { X := X, π := c.extensions.app (op X) f } @[simp] lemma extend_π (c : cone F) {X : Cᵒᵖ} (f : unop X ⟶ c.X) : (extend c f).π = c.extensions.app X f := rfl @[simps] def whisker {K : Type v} [small_category K] (E : K ⥤ J) (c : cone F) : cone (E ⋙ F) := { X := c.X, π := whisker_left E c.π } -- We now prove a lemma about naturality of cones over functors into bundled categories. section omit 𝒞 variables {J' : Type u} [small_category J'] variables {C' : Type (u+1)} [𝒞' : concrete_category C'] include 𝒞' local attribute [instance] concrete_category.has_coe_to_sort local attribute [instance] concrete_category.has_coe_to_fun /-- Naturality of a cone over functors to a concrete category. -/ @[simp] lemma naturality_concrete {G : J' ⥤ C'} (s : cone G) {j j' : J'} (f : j ⟶ j') (x : s.X) : (G.map f) ((s.π.app j) x) = (s.π.app j') x := begin convert congr_fun (congr_arg (λ k : s.X ⟶ G.obj j', (k : s.X → G.obj j')) (s.π.naturality f).symm) x; { dsimp, simp }, end end end cone namespace cocone def equiv (F : J ⥤ C) : cocone F ≅ Σ X, F.cocones.obj X := { hom := λ c, ⟨c.X, c.ι⟩, inv := λ c, { X := c.1, ι := c.2 }, hom_inv_id' := begin ext, cases x, refl, end, inv_hom_id' := begin ext, cases x, refl, end } @[simp] def extensions (c : cocone F) : coyoneda.obj (op c.X) ⟶ F.cocones := { app := λ X f, c.ι ≫ (const J).map f } /-- A map from the vertex of a cocone induces a cocone by composition. -/ @[simp] def extend (c : cocone F) {X : C} (f : c.X ⟶ X) : cocone F := { X := X, ι := c.extensions.app X f } @[simp] lemma extend_ι (c : cocone F) {X : C} (f : c.X ⟶ X) : (extend c f).ι = c.extensions.app X f := rfl @[simps] def whisker {K : Type v} [small_category K] (E : K ⥤ J) (c : cocone F) : cocone (E ⋙ F) := { X := c.X, ι := whisker_left E c.ι } -- We now prove a lemma about naturality of cocones over functors into bundled categories. section omit 𝒞 variables {J' : Type u} [small_category J'] variables {C' : Type (u+1)} [𝒞' : concrete_category C'] include 𝒞' local attribute [instance] concrete_category.has_coe_to_sort local attribute [instance] concrete_category.has_coe_to_fun /-- Naturality of a cocone over functors into a concrete category. -/ @[simp] lemma naturality_concrete {G : J' ⥤ C'} (s : cocone G) {j j' : J'} (f : j ⟶ j') (x : G.obj j) : (s.ι.app j') ((G.map f) x) = (s.ι.app j) x := begin convert congr_fun (congr_arg (λ k : G.obj j ⟶ s.X, (k : G.obj j → s.X)) (s.ι.naturality f)) x; { dsimp, simp }, end end end cocone @[ext] structure cone_morphism (A B : cone F) := (hom : A.X ⟶ B.X) (w' : ∀ j : J, hom ≫ B.π.app j = A.π.app j . obviously) restate_axiom cone_morphism.w' attribute [simp] cone_morphism.w @[simps] instance cone.category : category.{v} (cone F) := { hom := λ A B, cone_morphism A B, comp := λ X Y Z f g, { hom := f.hom ≫ g.hom, w' := by intro j; rw [assoc, g.w, f.w] }, id := λ B, { hom := 𝟙 B.X } } namespace cones /-- To give an isomorphism between cones, it suffices to give an isomorphism between their vertices which commutes with the cone maps. -/ @[ext, simps] def ext {c c' : cone F} (φ : c.X ≅ c'.X) (w : ∀ j, c.π.app j = φ.hom ≫ c'.π.app j) : c ≅ c' := { hom := { hom := φ.hom }, inv := { hom := φ.inv, w' := λ j, φ.inv_comp_eq.mpr (w j) } } @[simps] def postcompose {G : J ⥤ C} (α : F ⟶ G) : cone F ⥤ cone G := { obj := λ c, { X := c.X, π := c.π ≫ α }, map := λ c₁ c₂ f, { hom := f.hom, w' := by intro; erw ← category.assoc; simp [-category.assoc] } } def postcompose_comp {G H : J ⥤ C} (α : F ⟶ G) (β : G ⟶ H) : postcompose (α ≫ β) ≅ postcompose α ⋙ postcompose β := by { fapply nat_iso.of_components, { intro s, fapply ext, refl, obviously }, obviously } def postcompose_id : postcompose (𝟙 F) ≅ 𝟭 (cone F) := by { fapply nat_iso.of_components, { intro s, fapply ext, refl, obviously }, obviously } def postcompose_equivalence {G : J ⥤ C} (α : F ≅ G) : cone F ≌ cone G := begin refine equivalence.mk (postcompose α.hom) (postcompose α.inv) _ _, { symmetry, refine (postcompose_comp _ _).symm.trans _, rw [iso.hom_inv_id], exact postcompose_id }, { refine (postcompose_comp _ _).symm.trans _, rw [iso.inv_hom_id], exact postcompose_id } end @[simps] def forget : cone F ⥤ C := { obj := λ t, t.X, map := λ s t f, f.hom } section variables {D : Type u'} [𝒟 : category.{v} D] include 𝒟 @[simps] def functoriality (G : C ⥤ D) : cone F ⥤ cone (F ⋙ G) := { obj := λ A, { X := G.obj A.X, π := { app := λ j, G.map (A.π.app j), naturality' := by intros; erw ←G.map_comp; tidy } }, map := λ X Y f, { hom := G.map f.hom, w' := by intros; rw [←functor.map_comp, f.w] } } end end cones @[ext] structure cocone_morphism (A B : cocone F) := (hom : A.X ⟶ B.X) (w' : ∀ j : J, A.ι.app j ≫ hom = B.ι.app j . obviously) restate_axiom cocone_morphism.w' attribute [simp] cocone_morphism.w @[simps] instance cocone.category : category.{v} (cocone F) := { hom := λ A B, cocone_morphism A B, comp := λ _ _ _ f g, { hom := f.hom ≫ g.hom, w' := by intro j; rw [←assoc, f.w, g.w] }, id := λ B, { hom := 𝟙 B.X } } namespace cocones /-- To give an isomorphism between cocones, it suffices to give an isomorphism between their vertices which commutes with the cocone maps. -/ @[ext, simps] def ext {c c' : cocone F} (φ : c.X ≅ c'.X) (w : ∀ j, c.ι.app j ≫ φ.hom = c'.ι.app j) : c ≅ c' := { hom := { hom := φ.hom }, inv := { hom := φ.inv, w' := λ j, φ.comp_inv_eq.mpr (w j).symm } } @[simps] def precompose {G : J ⥤ C} (α : G ⟶ F) : cocone F ⥤ cocone G := { obj := λ c, { X := c.X, ι := α ≫ c.ι }, map := λ c₁ c₂ f, { hom := f.hom } } def precompose_comp {G H : J ⥤ C} (α : F ⟶ G) (β : G ⟶ H) : precompose (α ≫ β) ≅ precompose β ⋙ precompose α := by { fapply nat_iso.of_components, { intro s, fapply ext, refl, obviously }, obviously } def precompose_id : precompose (𝟙 F) ≅ 𝟭 (cocone F) := by { fapply nat_iso.of_components, { intro s, fapply ext, refl, obviously }, obviously } def precompose_equivalence {G : J ⥤ C} (α : G ≅ F) : cocone F ≌ cocone G := begin refine equivalence.mk (precompose α.hom) (precompose α.inv) _ _, { symmetry, refine (precompose_comp _ _).symm.trans _, rw [iso.inv_hom_id], exact precompose_id }, { refine (precompose_comp _ _).symm.trans _, rw [iso.hom_inv_id], exact precompose_id } end @[simps] def forget : cocone F ⥤ C := { obj := λ t, t.X, map := λ s t f, f.hom } section variables {D : Type u'} [𝒟 : category.{v} D] include 𝒟 @[simps] def functoriality (G : C ⥤ D) : cocone F ⥤ cocone (F ⋙ G) := { obj := λ A, { X := G.obj A.X, ι := { app := λ j, G.map (A.ι.app j), naturality' := by intros; erw ←G.map_comp; tidy } }, map := λ _ _ f, { hom := G.map f.hom, w' := by intros; rw [←functor.map_comp, cocone_morphism.w] } } end end cocones end limits namespace functor variables {D : Type u'} [category.{v} D] variables {F : J ⥤ C} {G : J ⥤ C} (H : C ⥤ D) open category_theory.limits /-- The image of a cone in C under a functor G : C ⥤ D is a cone in D. -/ def map_cone (c : cone F) : cone (F ⋙ H) := (cones.functoriality H).obj c /-- The image of a cocone in C under a functor G : C ⥤ D is a cocone in D. -/ def map_cocone (c : cocone F) : cocone (F ⋙ H) := (cocones.functoriality H).obj c @[simp] lemma map_cone_X (c : cone F) : (H.map_cone c).X = H.obj c.X := rfl @[simp] lemma map_cocone_X (c : cocone F) : (H.map_cocone c).X = H.obj c.X := rfl def map_cone_inv [is_equivalence H] (c : cone (F ⋙ H)) : cone F := let t := (inv H).map_cone c in let α : (F ⋙ H) ⋙ inv H ⟶ F := ((whisker_left F (is_equivalence.unit_iso H).inv) : F ⋙ (H ⋙ inv H) ⟶ _) ≫ (functor.right_unitor _).hom in { X := t.X, π := ((category_theory.cones J C).map α).app (op t.X) t.π } @[simp] lemma map_cone_inv_X [is_equivalence H] (c : cone (F ⋙ H)) : (H.map_cone_inv c).X = (inv H).obj c.X := rfl def map_cone_morphism {c c' : cone F} (f : cone_morphism c c') : cone_morphism (H.map_cone c) (H.map_cone c') := (cones.functoriality H).map f def map_cocone_morphism {c c' : cocone F} (f : cocone_morphism c c') : cocone_morphism (H.map_cocone c) (H.map_cocone c') := (cocones.functoriality H).map f @[simp] lemma map_cone_π (c : cone F) (j : J) : (map_cone H c).π.app j = H.map (c.π.app j) := rfl @[simp] lemma map_cocone_ι (c : cocone F) (j : J) : (map_cocone H c).ι.app j = H.map (c.ι.app j) := rfl end functor end category_theory namespace category_theory.limits variables {F : J ⥤ Cᵒᵖ} -- Here and below we only automatically generate the `@[simp]` lemma for the `X` field, -- as we can be a simpler `rfl` lemma for the components of the natural transformation by hand. @[simps X] def cone_of_cocone_left_op (c : cocone F.left_op) : cone F := { X := op c.X, π := nat_trans.right_op (c.ι ≫ (const.op_obj_unop (op c.X)).hom) } @[simp] lemma cone_of_cocone_left_op_π_app (c : cocone F.left_op) (j) : (cone_of_cocone_left_op c).π.app j = (c.ι.app (op j)).op := by { dsimp [cone_of_cocone_left_op], simp } @[simps X] def cocone_left_op_of_cone (c : cone F) : cocone (F.left_op) := { X := unop c.X, ι := nat_trans.left_op c.π } @[simp] lemma cocone_left_op_of_cone_ι_app (c : cone F) (j) : (cocone_left_op_of_cone c).ι.app j = (c.π.app (unop j)).unop := by { dsimp [cocone_left_op_of_cone], simp } @[simps X] def cocone_of_cone_left_op (c : cone F.left_op) : cocone F := { X := op c.X, ι := nat_trans.right_op ((const.op_obj_unop (op c.X)).hom ≫ c.π) } @[simp] lemma cocone_of_cone_left_op_ι_app (c : cone F.left_op) (j) : (cocone_of_cone_left_op c).ι.app j = (c.π.app (op j)).op := by { dsimp [cocone_of_cone_left_op], simp } @[simps X] def cone_left_op_of_cocone (c : cocone F) : cone (F.left_op) := { X := unop c.X, π := nat_trans.left_op c.ι } @[simp] lemma cone_left_op_of_cocone_π_app (c : cocone F) (j) : (cone_left_op_of_cocone c).π.app j = (c.ι.app (unop j)).unop := by { dsimp [cone_left_op_of_cocone], simp } end category_theory.limits