-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(Quiv): add the empty, vertex, point, interval, and walking quivers #24540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
45635ee
53d5cf2
f6d68e2
6c74351
537b85a
55aa2fb
b6771ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| /- | ||
| Copyright (c) 2025 Robert Maxton. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Robert Maxton | ||
| -/ | ||
|
|
||
| import Mathlib.CategoryTheory.Category.Quiv | ||
| import Mathlib.CategoryTheory.Limits.Shapes.Terminal | ||
| import Mathlib.CategoryTheory.Generator.Basic | ||
|
|
||
| /-!# Shapes in Quiv | ||
|
|
||
| In this file, we define a number of quivers, most of which have corresponding notations: | ||
| * The `Empty` quiver, which is initial | ||
| * The single-vertex zero-edge quiver `Vert`, with the notation `⋆` | ||
| * The single-vertex single-edge quiver `Point`, with the notation `⭮`, which is terminal | ||
| * The `Interval` quiver, with the notation `𝕀` | ||
|
|
||
| All notations are duplicated: once for when universe levels can be inferred, and once to | ||
| allow explicit universe levels to be given. | ||
|
|
||
| ## TODO | ||
| * The subobject classifier in `Quiv` | ||
|
|
||
| -/ | ||
|
|
||
| namespace CategoryTheory.Quiv | ||
| universe v u v₁ u₁ v₂ u₂ | ||
| open Limits | ||
|
|
||
| /-- The empty quiver, with no vertices and no edges. -/ | ||
| def Empty := let _ := PUnit.{v}; PEmpty.{u + 1} | ||
|
|
||
| instance : Quiver.{v + 1} Empty.{v} where | ||
| Hom _ _ := PEmpty | ||
|
|
||
| instance : IsEmpty Empty where | ||
| false := PEmpty.elim | ||
|
|
||
| /-- The single-vertex quiver, with one vertex and no edges. -/ | ||
| def Vert := let _ := PUnit.{v}; PUnit.{u + 1} | ||
|
|
||
| instance : Quiver.{v + 1} Vert.{v} where | ||
| Hom _ _ := PEmpty | ||
|
|
||
| @[inherit_doc Vert] scoped notation "⋆" => Vert | ||
| set_option quotPrecheck false in | ||
| @[inherit_doc Vert] scoped notation "⋆.{" v ", " u "}" => Vert.{v, u} | ||
|
|
||
| /-- Prefunctors out of `⋆` are just single objects. -/ | ||
| def Vert.prefunctor {V : Type u₂} [Quiver.{v₂} V] (v : V) : ⋆.{v₁, u₁} ⥤q V := | ||
| {obj := fun _ ↦ v, map := nofun} | ||
|
|
||
| /-- Prefunctors out of `⋆` are equal if they point to the same object. -/ | ||
| @[ext] | ||
| lemma Vert.prefunctor.ext {V : Type u₂} [Quiver.{v₂} V] {F G : ⋆.{v₁, u₁} ⥤q V} | ||
| (h : F.obj ⟨⟩ = G.obj ⟨⟩) : F = G := by | ||
| rcases F with ⟨F_obj, F_map⟩; rcases G with ⟨G_obj, G_map⟩ | ||
| simp at h | ||
| rw [Prefunctor.mk.injEq] | ||
| constructor | ||
| · ext ⟨⟩; exact h | ||
| · apply Function.hfunext rfl | ||
| rintro ⟨⟩ ⟨⟩ - | ||
| apply Function.hfunext rfl | ||
| rintro ⟨⟩ ⟨⟩ - | ||
| apply Function.hfunext rfl | ||
| rintro ⟨⟩ | ||
|
|
||
| /-- The interval quiver, with two points and a single edge `.left ⟶ .right`. -/ | ||
| def Interval := let _ := PUnit.{v}; ULift.{u} WalkingPair | ||
|
|
||
| instance : Quiver.{v + 1} Interval.{v} where | ||
| Hom | ||
| | .up .left, .up .right => PUnit | ||
| | _, _ => PEmpty | ||
|
|
||
| @[inherit_doc Interval] scoped notation "𝕀" => Interval | ||
| set_option quotPrecheck false in | ||
| @[inherit_doc Interval] scoped notation "𝕀.{" v ", " u "}" => Interval.{v, u} | ||
|
|
||
| /-- The left point of `𝕀`. -/ | ||
| @[match_pattern] def Interval.left : 𝕀 := .up .left | ||
| /-- The right point of `𝕀`. -/ | ||
| @[match_pattern] def Interval.right : 𝕀 := .up .right | ||
|
|
||
| @[match_pattern] alias 𝕀.left := Interval.left | ||
| @[match_pattern] alias 𝕀.right := Interval.right | ||
|
|
||
| @[simps] instance : Zero 𝕀 := ⟨Interval.left⟩ | ||
| @[simps] instance : One 𝕀 := ⟨Interval.right⟩ | ||
|
|
||
| /-- The single edge of `𝕀`. -/ | ||
| @[simp, match_pattern] def Interval.hom : (0 : 𝕀.{v, u}) ⟶ 1 := ⟨⟩ | ||
|
|
||
| alias 𝕀.hom := Interval.hom | ||
|
|
||
| /-- Convenience eliminator for building data on `𝕀.hom`. | ||
|
|
||
| Can't be a `cases_eliminator` or Lean will try to use it on every morphism in every quiver. -/ | ||
| @[elab_as_elim] | ||
| def Interval.casesOn_hom {motive : {X Y : 𝕀} → (X ⟶ Y) → Sort*} | ||
| {X Y : 𝕀} (f : X ⟶ Y) (hom : motive Interval.hom) : motive f := | ||
| match X, Y, f with | ||
| | Interval.left, Interval.right, _ => hom | ||
|
|
||
| /-- Prefunctors out of `𝕀` are just single homs. -/ | ||
| def Interval.prefunctor {V : Type u₂} [Quiver.{v₂} V] {X Y : V} (f : X ⟶ Y) : 𝕀.{u₁, v₁} ⥤q V := | ||
| { obj := fun | Interval.left => X | Interval.right => Y, | ||
| map := @fun | Interval.left, Interval.right, Interval.hom => f } | ||
|
|
||
| /-- Prefunctors out of `𝕀` are equal if they point to the same hom. -/ | ||
| @[ext (iff := false)] | ||
| lemma Interval.prefunctor.ext {V : Type u₂} [Quiver.{v₂} V] {F G : 𝕀.{u₁, v₁} ⥤q V} | ||
| (h₀ : F.obj 0 = G.obj 0) (h₁ : F.obj 1 = G.obj 1) | ||
| (h : F.map Interval.hom = Quiver.homOfEq (G.map Interval.hom) h₀.symm h₁.symm) : F = G := by | ||
| rcases F with ⟨F_obj, F_map⟩; rcases G with ⟨G_obj, G_map⟩ | ||
| -- simp at h₀ h₁ h | ||
| rw [Prefunctor.mk.injEq] | ||
| constructor | ||
| · ext (Interval.left | Interval.right) <;> simpa | ||
| · apply Function.hfunext rfl | ||
| rintro X X' ⟨⟩ | ||
| apply Function.hfunext rfl | ||
| rintro Y Y' ⟨⟩ | ||
| apply Function.hfunext rfl | ||
| simp_rw [heq_eq_eq, forall_eq'] | ||
| rintro f | ||
| cases f using Interval.casesOn_hom | ||
| simp at h | ||
| simp [h, Quiver.homOfEq_heq] | ||
|
|
||
| lemma Interval.prefunctor.ext_iff {V : Type u₂} [Quiver.{v₂} V] {F G : 𝕀.{u₁, v₁} ⥤q V} : | ||
| F = G ↔ ∃ (h₀ : F.obj 0 = G.obj 0) (h₁ : F.obj 1 = G.obj 1), | ||
| F.map Interval.hom = Quiver.homOfEq (G.map Interval.hom) h₀.symm h₁.symm := by | ||
| refine ⟨fun h => ?_, fun ⟨h₀, h₁, h⟩ => Interval.prefunctor.ext h₀ h₁ h⟩ | ||
| subst h; simp | ||
|
|
||
| /-- The topos-theory point as a quiver, with a single point (vertex with a self-loop) and no other | ||
| vertices or edges. -/ | ||
| def Point := let _ := PUnit.{v}; PUnit.{u + 1} | ||
|
|
||
| instance : Quiver.{v + 1} Point.{v} where | ||
| Hom _ _ := PUnit | ||
|
|
||
| @[inherit_doc Point] scoped notation "⭮" => Point | ||
| set_option quotPrecheck false in | ||
| @[inherit_doc Point] scoped notation "⭮.{" v ", " u "}" => Point.{v, u} | ||
|
|
||
| /-- Prefunctors out of `⭮` are just single self-arrows. -/ | ||
| def Point.prefunctor {V : Type u₂} [Quiver.{v₂} V] {v : V} (α : v ⟶ v) : ⭮.{v₁, u₁} ⥤q V := | ||
| {obj := fun _ ↦ v, map := fun _ => α} | ||
|
|
||
| /-- Prefunctors out of `⭮` are equal if they point to the same self-arrow. -/ | ||
| @[ext (iff := false)] | ||
| lemma Point.prefunctor.ext {V : Type u₂} [Quiver.{v₂} V] {F G : ⭮.{v₁, u₁} ⥤q V} | ||
| (h_obj : F.obj ⟨⟩ = G.obj ⟨⟩) | ||
| (h_map : F.map ⟨⟩ = Quiver.homOfEq (G.map ⟨⟩) h_obj.symm h_obj.symm) : F = G := by | ||
| rcases F with ⟨F_obj, F_map⟩; rcases G with ⟨G_obj, G_map⟩ | ||
| rw [Prefunctor.mk.injEq] | ||
| constructor | ||
| · ext ⟨⟩; exact h_obj | ||
| · apply Function.hfunext rfl | ||
| rintro ⟨⟩ ⟨⟩ - | ||
| apply Function.hfunext rfl | ||
| rintro ⟨⟩ ⟨⟩ - | ||
| apply Function.hfunext rfl | ||
| simp only [heq_eq_eq, forall_eq'] | ||
| rintro ⟨⟩ | ||
| simp at h_map | ||
| simp [h_map, Quiver.homOfEq_heq] | ||
|
|
||
| lemma Point.prefunctor.ext_iff {V : Type u₂} [Quiver.{v₂} V] {F G : ⭮.{v₁, u₁} ⥤q V} : | ||
| F = G ↔ ∃ h_obj : F.obj ⟨⟩ = G.obj ⟨⟩, | ||
| F.map ⟨⟩ = Quiver.homOfEq (G.map ⟨⟩) h_obj.symm h_obj.symm := by | ||
| refine ⟨fun h => ?_, fun ⟨h_obj, h_map⟩ => Point.prefunctor.ext h_obj h_map⟩ | ||
| subst h; simp | ||
|
|
||
| /-- `Empty` is initial in **`Quiv`**. -/ | ||
| def emptyIsInitial : IsInitial (of Empty) := | ||
| IsInitial.ofUniqueHom (fun X ↦ Prefunctor.mk PEmpty.elim PEmpty.elim) | ||
| fun X ⟨obj, map⟩ ↦ by | ||
| congr | ||
| · ext ⟨⟩ | ||
| · apply Function.hfunext rfl | ||
| rintro ⟨⟩ | ||
|
|
||
| instance : HasInitial Quiv := emptyIsInitial.hasInitial | ||
|
|
||
| /-- The initial object in **Quiv** is `Empty`. -/ | ||
| noncomputable def initialIsoEmpty : ⊥_ Quiv ≅ of Empty := | ||
| initialIsoIsInitial emptyIsInitial | ||
|
|
||
| /-- `⭮` is terminal in **Quiv**. -/ | ||
| def pointIsTerminal : IsTerminal (of ⭮) := | ||
| IsTerminal.ofUniqueHom | ||
| (fun X ↦ Prefunctor.mk (fun _ ↦ ⟨⟩) (fun _ ↦ ⟨⟩)) | ||
| fun X ⟨obj, map⟩ ↦ by congr | ||
|
|
||
| instance : HasTerminal Quiv := pointIsTerminal.hasTerminal | ||
|
|
||
| /-- The terminal object in **Quiv** is ⭮. -/ | ||
| noncomputable def terminalIsoPoint : ⊤_ Quiv ≅ of ⭮ := | ||
| terminalIsoIsTerminal pointIsTerminal | ||
|
|
||
| end Quiv | ||
| end CategoryTheory | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| import Mathlib.CategoryTheory.Category.Quiv | ||
|
Check warning on line 1 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean
|
||
| import Mathlib.Data.Fintype.Basic | ||
| import Mathlib.CategoryTheory.ConcreteCategory.Basic | ||
|
|
||
| import Mathlib.Tactic.ApplyFun | ||
| -- import Mathlib.Tactic.finCases | ||
|
|
||
| open CategoryTheory | ||
|
Check warning on line 8 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean
|
||
|
|
||
| inductive WalkingQuiver where | zero | one deriving Inhabited | ||
|
|
||
| -- instance : Fintype WalkingQuiver := Fin.fintype 2 | ||
|
|
||
| instance : OfNat WalkingQuiver 0 := ⟨WalkingQuiver.zero⟩ | ||
| instance : OfNat WalkingQuiver 1 := ⟨WalkingQuiver.one⟩ | ||
|
|
||
| -- set `0` and `1` as simp normal forms | ||
| @[simp] | ||
| lemma zero_eq : WalkingQuiver.zero = 0 := rfl | ||
| @[simp] | ||
| lemma one_eq : WalkingQuiver.one = 1 := rfl | ||
|
|
||
| -- instance : Zero WalkingQuiver := ⟨WalkingQuiver.zero⟩ | ||
| -- instance : One WalkingQuiver := ⟨WalkingQuiver.one⟩ | ||
|
|
||
| -- Delaborators to use `0` and `1` instead of `WalkingQuiver.zero` and `WalkingQuiver.one` | ||
|
|
||
| @[delab app.WalkingQuiver.zero] | ||
| def delabWalkingQuiverZero : Lean.PrettyPrinter.Delaborator.Delab := do | ||
| return ← `(0) | ||
|
|
||
| @[delab app.WalkingQuiver.one] | ||
| def delabWalkingQuiverOne : Lean.PrettyPrinter.Delaborator.Delab := do | ||
| return ← `(1) | ||
|
|
||
|
|
||
|
|
||
|
|
||
| inductive WalkingQuiver.Hom : WalkingQuiver → WalkingQuiver → Type | ||
| | id X : WalkingQuiver.Hom X X | ||
| | source : WalkingQuiver.Hom .one .zero | ||
| | target: WalkingQuiver.Hom .one .zero | ||
|
|
||
| def WalkingQuiver.forget : WalkingQuiver → Type | ||
| | .zero => Bool | ||
| | .one => Unit | ||
|
|
||
| instance (X Y : WalkingQuiver) : | ||
| FunLike (WalkingQuiver.Hom X Y) (WalkingQuiver.forget X) (WalkingQuiver.forget Y) where | ||
| coe | ||
| | .id X => id | ||
| | .source => fun _ => false | ||
| | .target => fun _ => true | ||
| coe_injective' X Y f := by | ||
| cases X <;> cases Y <;> simp_all [funext_iff, WalkingQuiver.forget] | ||
|
|
||
| instance : Category WalkingQuiver where | ||
| Hom := WalkingQuiver.Hom | ||
| id := WalkingQuiver.Hom.id | ||
| comp | ||
| | WalkingQuiver.Hom.id _, g => g | ||
| | f, WalkingQuiver.Hom.id _ => f | ||
| id_comp f := by cases f <;> rfl | ||
| comp_id f := by cases f <;> rfl | ||
| assoc {W X Y Z} f g h := by | ||
| cases Z; swap | ||
| · cases h; cases g; cases f; rfl | ||
| · cases Y; swap | ||
| · cases g; cases f; cases h <;> rfl | ||
| · cases h | ||
| cases X; swap | ||
| · cases f; cases g <;> rfl | ||
| · cases g; cases f <;> rfl | ||
|
|
||
| #check instCategoryWalkingQuiver.match_1 | ||
|
|
||
| instance : ConcreteCategory WalkingQuiver WalkingQuiver.Hom where | ||
| hom := id | ||
| ofHom := id | ||
| comp_apply {X Y Z} f g X' := by | ||
| simp [instCategoryWalkingQuiver] | ||
| cases Y | ||
| · cases X | ||
| · cases f; simp; rfl | ||
| · cases Z | ||
| · cases g; cases f <;> {simp; rfl} | ||
| · cases g | ||
| · cases X | ||
| · cases f | ||
| · cases f; cases g <;> {simp; rfl} | ||
|
|
||
| namespace WalkingQuiver | ||
|
|
||
| /-- Convenience recursor for `WalkingQuiver` in terms of the notation `0` and `1`. -/ | ||
| @[elab_as_elim, cases_eliminator] | ||
| def casesOn' {motive : WalkingQuiver → Sort*} | ||
| (m : WalkingQuiver) (zero : motive 0) (one : motive 1) : motive m := | ||
| match m with | 0 => zero | 1 => one | ||
|
|
||
| @[simp] | ||
| lemma id_def (X : WalkingQuiver) : WalkingQuiver.Hom.id X = 𝟙 X := rfl | ||
|
|
||
| @[simp] | ||
| lemma hom₀₁_empty : IsEmpty ((0 : WalkingQuiver) ⟶ 1) := ⟨by rintro ⟨⟩⟩ | ||
|
|
||
| /-- Any function out of `WalkingQuiver` can be represented as a pair of values for `0` and `1`. -/ | ||
| def funByCases {α : WalkingQuiver → Sort*} : ((m : WalkingQuiver) → α m) ≃ (α 0 ×' α 1) := | ||
| { toFun := fun f => ⟨f 0, f 1⟩, | ||
| invFun := fun ⟨f₀, f₁⟩ => fun | 0 => f₀ | 1 => f₁, | ||
| left_inv := fun f => by ext x; cases x <;> rfl, | ||
| right_inv := fun ⟨f₀, f₁⟩ => by simp } | ||
|
|
||
|
|
||
| @[elab_as_elim] | ||
| def casesOn_fun {α : WalkingQuiver → Sort*} {motive : ((m : WalkingQuiver) → α m) → Sort*} | ||
| (f : (m : WalkingQuiver) → α m) (split : motive (fun | 0 => f 0 | 1 => f 1)) : | ||
| motive f := by | ||
| convert split with m; cases m <;> simp | ||
|
|
||
| lemma funByCases_eq {α : WalkingQuiver → Sort*} (f : (m : WalkingQuiver) → α m) : | ||
| f = fun | 0 => f 0 | 1 => f 1 := by | ||
| ext x; cases x <;> rfl | ||
|
|
||
| lemma forall_byCases {p : WalkingQuiver → Prop} : | ||
| (∀ m, p m) ↔ p 0 ∧ p 1 where | ||
| mp h := by simp [h] | ||
| mpr := fun ⟨h₀, h₁⟩ m ↦ by cases m <;> assumption | ||
|
|
||
| @[simp] | ||
| lemma forall₀₀ {p : ((0 : WalkingQuiver) ⟶ 0) → Prop} : (∀ f, p f) ↔ p (𝟙 0) where | ||
| mp h := h _ | ||
| mpr h := fun f ↦ by cases f; exact h | ||
|
|
||
| @[simp] | ||
| lemma forall₁₁ {p : ((1 : WalkingQuiver) ⟶ 1) → Prop} : (∀ f, p f) ↔ p (𝟙 1) where | ||
| mp h := h _ | ||
| mpr h := fun f ↦ by cases f; exact h | ||
|
|
||
| @[simp] | ||
| lemma forall₀₁ {p : ((0 : WalkingQuiver) ⟶ 1) → Prop} : (∀ f, p f) ↔ True where | ||
| mp _ := trivial | ||
| mpr _ := nofun | ||
|
|
||
| @[simp] | ||
| lemma forall₁₀ {p : ((1 : WalkingQuiver) ⟶ 0) → Prop} : (∀ f, p f) ↔ p .source ∧ p .target where | ||
| mp h := by simp [h] | ||
| mpr := fun ⟨h₀, h₁⟩ f ↦ by cases f <;> assumption | ||
|
|
||
| @[simp] | ||
| lemma forallHom_byCases {p : {m₁ m₂ : WalkingQuiver} → (m₁ ⟶ m₂) → Prop} : | ||
| (∀ {m₁ m₂} (f : m₁ ⟶ m₂), p f) ↔ (∀ m, p (𝟙 m)) ∧ p .source ∧ p .target where | ||
| mp h := by simp [h] | ||
| mpr := fun ⟨h_id, h_src, h_tgt⟩ m₁ m₂ f ↦ by | ||
| cases f with | ||
| | id => cases m₁ <;> simp_all | ||
| | _ => simp_all | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,11 @@ def Shrink (α : Type v) [Small.{w} α] : Type w := | |
| noncomputable def equivShrink (α : Type v) [Small.{w} α] : α ≃ Shrink α := | ||
| Nonempty.some (Classical.choose_spec (@Small.equiv_small α _)) | ||
|
|
||
| /-- Extract the underlying element of a `Shrink` object using projection notation. -/ | ||
| @[simp] | ||
| noncomputable def Shrink.out {α : Type v} [Small.{w} α] (x : Shrink α) : α := | ||
| (equivShrink α).symm x | ||
|
|
||
|
Comment on lines
+49
to
+53
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not think we want/need this definition (which seems to be unused in the rest of the PR).
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is used in a following PR on (co)limits in Quivers, where it greatly simplifies notation by enabling the projection notation: That said, I forget why I lumped it into this PR. |
||
| @[ext] | ||
| theorem Shrink.ext {α : Type v} [Small.{w} α] {x y : Shrink α} | ||
| (w : (equivShrink _).symm x = (equivShrink _).symm y) : x = y := by | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitions of quivers should rather be in the folder
Combinatorics.Quiver. For the naming conventions, instead ofQuiv.Empty, we should useQuiver.Empty(seeCombinatorics.Quiver.SingleObjfor example).