module Cat.Instances.Graphs where
private variable
: Level o o' ℓ ℓ'
The category of graphs🔗
A graph (really, an 1) is given by a set of vertices and, for each pair of elements a set of edges from to That’s it: a set and a family of sets over
record Graph (o ℓ : Level) : Type (lsuc o ⊔ lsuc ℓ) where
no-eta-equality
field
: Type o
Vertex : Vertex → Vertex → Type ℓ
Edge : is-set Vertex
Vertex-is-set : ∀ {x y} → is-set (Edge x y) Edge-is-set
open Graph
open hlevel-projection
instance
: Underlying (Graph o ℓ)
Underlying-Graph = record { ⌞_⌟ = Graph.Vertex }
Underlying-Graph
: hlevel-projection (quote Graph.Vertex)
hlevel-proj-vertex .has-level = quote Graph.Vertex-is-set
hlevel-proj-vertex .get-level _ = pure (quoteTerm (suc (suc zero)))
hlevel-proj-vertex .get-argument (_ ∷ _ ∷ c v∷ _) = pure c
hlevel-proj-vertex {-# CATCHALL #-}
.get-argument _ = typeError []
hlevel-proj-vertex
: hlevel-projection (quote Graph.Edge)
hlevel-proj-edge .has-level = quote Graph.Edge-is-set
hlevel-proj-edge .get-level _ = pure (quoteTerm (suc (suc zero)))
hlevel-proj-edge .get-argument (_ ∷ _ ∷ c v∷ _) = pure c
hlevel-proj-edge {-# CATCHALL #-}
.get-argument _ = typeError [] hlevel-proj-edge
A graph homomorphism consists of a mapping of vertices along with a mapping of edges
record Graph-hom (G : Graph o ℓ) (H : Graph o' ℓ') : Type (o ⊔ o' ⊔ ℓ ⊔ ℓ') where
no-eta-equality
field
: ⌞ G ⌟ → ⌞ H ⌟
vertex : ∀ {x y} → G .Edge x y → H .Edge (vertex x) (vertex y) edge
private variable
: Graph o ℓ
G H K
open Graph-hom
unquoteDecl H-Level-Graph-hom = declare-record-hlevel 2 H-Level-Graph-hom (quote Graph-hom)
Graph-hom-pathp: {G : I → Graph o ℓ} {H : I → Graph o' ℓ'}
→ {f : Graph-hom (G i0) (H i0)} {g : Graph-hom (G i1) (H i1)}
→ (p0 : ∀ (x : ∀ i → G i .Vertex)
→ PathP (λ i → H i .Vertex)
(f .vertex (x i0)) (g .vertex (x i1)))
→ (p1 : ∀ {x y : ∀ i → G i .Vertex}
→ (e : ∀ i → G i .Edge (x i) (y i))
→ PathP (λ i → H i .Edge (p0 x i) (p0 y i))
(f .edge (e i0)) (g .edge (e i1)))
→ PathP (λ i → Graph-hom (G i) (H i)) f g
{G = G} {H = H} {f = f} {g = g} p0 p1 = pathp where
Graph-hom-pathp : I → Type _
vertex* = (G i) .Vertex
vertex* i
: (i : I) → vertex* i → vertex* i → Type _
edge* = (G i) .Edge x y
edge* i x y
: PathP (λ i → Graph-hom (G i) (H i)) f g
pathp .vertex x = p0 (λ j → coe vertex* i j x) i
pathp i .edge {x} {y} e =
pathp i {x = λ j → coe vertex* i j x} {y = λ j → coe vertex* i j y}
p1 (λ j → coe (λ j → edge* j (coe vertex* i j x) (coe vertex* i j y)) i j (e* j)) i
where
: (j : I) → vertex* i
x* y* = coei→i vertex* i x (~ j ∨ i)
x* j = coei→i vertex* i y (~ j ∨ i)
y* j
: (j : I) → edge* i (coe vertex* i i x) (coe vertex* i i y)
e* =
e* j (λ j → edge* i (x* j) (y* j)) ((~ i ∧ ~ j) ∨ (i ∧ j)) λ where
comp (k = i0) → e
k (i = i0) (j = i0) → e
k (i = i1) (j = i1) → e
k
Graph-hom-path: {f g : Graph-hom G H}
→ (p0 : ∀ x → f .vertex x ≡ g .vertex x)
→ (p1 : ∀ {x y} → (e : Graph.Edge G x y) → PathP (λ i → Graph.Edge H (p0 x i) (p0 y i)) (f .edge e) (g .edge e))
→ f ≡ g
{G = G} {H = H} p0 p1 =
Graph-hom-path {G = λ _ → G} {H = λ _ → H}
Graph-hom-pathp (λ x i → p0 (x i) i)
(λ e i → p1 (e i) i)
instance
: Funlike (Graph-hom G H) ⌞ G ⌟ λ _ → ⌞ H ⌟
Funlike-Graph-hom .Funlike._#_ = vertex Funlike-Graph-hom
Graphs and graph homomorphisms can be organized into a category
: ∀ o ℓ → Precategory (lsuc (o ⊔ ℓ)) (o ⊔ ℓ)
Graphs .Precategory.Ob = Graph o ℓ
Graphs o ℓ .Precategory.Hom = Graph-hom
Graphs o ℓ .Precategory.Hom-set _ _ = hlevel 2
Graphs o ℓ .Precategory.id .vertex v = v
Graphs o ℓ .Precategory.id .edge e = e
Graphs o ℓ .Precategory._∘_ f g .vertex v = f .vertex (g .vertex v)
Graphs o ℓ .Precategory._∘_ f g .edge e = f .edge (g .edge e)
Graphs o ℓ .Precategory.idr _ = Graph-hom-path (λ _ → refl) (λ _ → refl)
Graphs o ℓ .Precategory.idl _ = Graph-hom-path (λ _ → refl) (λ _ → refl)
Graphs o ℓ .Precategory.assoc _ _ _ = Graph-hom-path (λ _ → refl) (λ _ → refl)
Graphs o ℓ
module Graphs {o} {ℓ} = Cat.Reasoning (Graphs o ℓ)
open Functor
Note that every strict category has an underlying graph, where the vertices are given by objects, and edges by morphisms. Moreover, functors between strict categories give rise to graph homomorphisms between underlying graphs. This gives rise to a functor from the category of strict categories to the category of graphs.
: Functor (Strict-cats o ℓ) (Graphs o ℓ)
Strict-cats↪Graphs .F₀ (C , C-strict) .Vertex = Precategory.Ob C
Strict-cats↪Graphs .F₀ (C , C-strict) .Edge = Precategory.Hom C
Strict-cats↪Graphs .F₀ (C , C-strict) .Vertex-is-set = C-strict
Strict-cats↪Graphs .F₀ (C , C-strict) .Edge-is-set = Precategory.Hom-set C _ _
Strict-cats↪Graphs .F₁ F .vertex = F .F₀
Strict-cats↪Graphs .F₁ F .edge = F .F₁
Strict-cats↪Graphs .F-id = Graph-hom-path (λ _ → refl) (λ _ → refl)
Strict-cats↪Graphs .F-∘ F G = Graph-hom-path (λ _ → refl) (λ _ → refl) Strict-cats↪Graphs
The underlying graph functor is faithful, as functors are graph homomorphisms with extra properties.
: is-faithful (Strict-cats↪Graphs {o} {ℓ})
Strict-cats↪Graphs-faithful =
Strict-cats↪Graphs-faithful p
Functor-path(λ x i → p i .vertex x)
(λ e i → p i .edge e)
and, even more pedantically, a directed multi-↩︎