Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,8 @@ import Mathlib.CategoryTheory.Category.PartialFun
import Mathlib.CategoryTheory.Category.Pointed
import Mathlib.CategoryTheory.Category.Preorder
import Mathlib.CategoryTheory.Category.Quiv
import Mathlib.CategoryTheory.Category.Quiv.Shapes
import Mathlib.CategoryTheory.Category.Quiv.WalkingQuiver
import Mathlib.CategoryTheory.Category.ReflQuiv
import Mathlib.CategoryTheory.Category.RelCat
import Mathlib.CategoryTheory.Category.TwoP
Expand Down
207 changes: 207 additions & 0 deletions Mathlib/CategoryTheory/Category/Quiv/Shapes.lean
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}
Copy link
Copy Markdown
Contributor

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 of Quiv.Empty, we should use Quiver.Empty (see Combinatorics.Quiver.SingleObj for example).


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
156 changes: 156 additions & 0 deletions Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean
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

View workflow job for this annotation

GitHub Actions / Build

* '-/':

Check warning on line 1 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

* '-/':

Check warning on line 1 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

* '-/':

Check warning on line 1 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

* '-/':

Check warning on line 1 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

* '-/':
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

View workflow job for this annotation

GitHub Actions / Build

The module doc-string for a file should be the first command after the imports.

Check warning on line 8 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

The module doc-string for a file should be the first command after the imports.

Check warning on line 8 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

The module doc-string for a file should be the first command after the imports.

Check warning on line 8 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

The module doc-string for a file should be the first command after the imports.

Check warning on line 8 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

The module doc-string for a file should be the first command after the imports.

inductive WalkingQuiver where | zero | one deriving Inhabited

Check failure on line 10 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

WalkingQuiver inductive missing documentation string

-- 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]

Check failure on line 28 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

delabWalkingQuiverZero definition missing documentation string
def delabWalkingQuiverZero : Lean.PrettyPrinter.Delaborator.Delab := do
return ← `(0)

@[delab app.WalkingQuiver.one]

Check failure on line 32 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

delabWalkingQuiverOne definition missing documentation string
def delabWalkingQuiverOne : Lean.PrettyPrinter.Delaborator.Delab := do
return ← `(1)




inductive WalkingQuiver.Hom : WalkingQuiver → WalkingQuiver → Type

Check failure on line 39 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

WalkingQuiver.Hom inductive missing documentation string
| id X : WalkingQuiver.Hom X X
| source : WalkingQuiver.Hom .one .zero
| target: WalkingQuiver.Hom .one .zero

def WalkingQuiver.forget : WalkingQuiver → Type

Check failure on line 44 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

WalkingQuiver.forget definition missing documentation string
| .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]

Check failure on line 114 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

@WalkingQuiver.casesOn_fun definition missing documentation string
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]

Check failure on line 139 in Mathlib/CategoryTheory/Category/Quiv/WalkingQuiver.lean

View workflow job for this annotation

GitHub Actions / Build

@WalkingQuiver.forall₀₁ simp can prove this:
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
5 changes: 5 additions & 0 deletions Mathlib/Logic/Small/Defs.lean
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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).

Copy link
Copy Markdown
Collaborator Author

@robertmaxton42 robertmaxton42 Jun 6, 2025

Choose a reason for hiding this comment

The 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: x.out versus having (equivShrink _).symm x everywhere.

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
Expand Down
Loading