example theorem

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(χ)                                 # true
import 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