The category of directed graphs is a presheaf Topos: graphs are presheaves on the arrow shape , i.e. instances on the schema (Example 7.23). Its Subobject Classifier is itself a graph with two vertices and five arrows:
The terminal graph is one vertex with one loop, and sends that loop to .
Sources: 7 Sketches Example 7.23 (“presheaves on are just directed graphs”, “a graph is a sort of lego construction”), Example 7.54, Exercise 7.55, [Vig03]; Kittenlab Lecture 6 (graphs as C-sets).
Classifying a subgraph. Given , the characteristic map records “how much of each part is in ”: a vertex goes to if it is in and to otherwise; an arrow in goes to ; an arrow not in goes to , , or according to whether its source and target are in . See 7S Exercise 7.55. The name of each arrow of lists which of (source, target; arrow) are present — this is what the Yoneda Lemma produces: is the set of subobjects of the representable .
The lattice is a Heyting Algebra but not Boolean: the negation of a subgraph is the largest subgraph disjoint from , so an edge touching is in neither nor (Internal Logic of a Topos).
Docs: Limits & colimits · Categories & functors · C-set morphisms · Graphs · Vignette: subgraphs — Kittenlab Lecture 6
using Catlab
Ω, subs = subobject_classifier(Graph)
Ω # Graph: V = 1:2, E = 1:5, src = [1,1,1,2,2], tgt = [1,1,2,1,2]
# vertex 1 = V ("present"), vertex 2 = 0 ("absent");
# edges: 1 = (V,V;A), 2 = (V,V;0), 3 = (V,0;0), 4 = (0,V;0), 5 = (0,0;0)
subs[:E] # the five subobjects of the representable edge that name these arrows
T = ob(terminal(Graph)) # one vertex, one loop
# classify a subgraph: the unique hom G → Ω pulling `true` (loop ↦ edge 1) back to H
G = path_graph(Graph, 3); H = Subobject(G, V=[1, 2], E=[1])
χ = ACSetTransformation(G, Ω; V=[1, 1, 2], E=[1, 3]) # ⌜H⌝: vertices 1,2 present, 3 absent
is_natural(χ) # trueimport Mathlib
open CategoryTheory
-- presheaf categories are toposes; Mathlib has the classifier for `Type` and general sheaf machinery
#check @CategoryTheory.Functor -- Grph ≃ (ArShpᵒᵖ ⥤ Type)
#check @CategoryTheory.Subobject -- Sub(G) for a presheaf G-- the five "truth values" for an arrow of a graph, and the two for a vertex
data OmegaV = Absent | Present deriving (Eq, Show)
data OmegaE = E00 | E0V | EV0 | EVV0 | EVVA deriving (Eq, Show)
classifyEdge :: Bool -> Bool -> Bool -> OmegaE -- (source in H, target in H, edge in H)
classifyEdge True True True = EVVA
classifyEdge True True False = EVV0
classifyEdge True False _ = EV0
classifyEdge False True _ = E0V
classifyEdge False False _ = E00