using Pkg; Pkg.activate(".")
using Catlab
using Catlab.Graphs
= path_graph(Graph, 10) g
E | src | tgt |
---|---|---|
1 | 1 | 2 |
2 | 2 | 3 |
3 | 3 | 4 |
4 | 4 | 5 |
5 | 5 | 6 |
6 | 6 | 7 |
7 | 7 | 8 |
8 | 8 | 9 |
9 | 9 | 10 |
$$
$$
The core of category theory is the idea that “everything you know” about an object is encapsulated by looking at the morphisms out of (or into) that object.
This intuition is captured in the formalism of representable functors, which we have talked about before but hasn’t seemed to “take”.
Before we (re)define representable functors, we’re going to talk a little bit about the “type” of a representable functor.
We want to look at the morphisms out of an object. How can we express that information? One way would be to just have a set. But that doesn’t tell us very much; that doesn’t give us “handles” that we can use to process the information.
We can organize a little bit by splitting that set by codomain. Namely, for each object Y \in \mathsf{C}, we have a set of morphisms with codomain Y. So this looks like a function F \colon \mathsf{C}\to \mathsf{Set}. But when we have a morphism from Y to Z, and a morphism into Y, then we can make a morphism into Z. Thus, for every f \colon Y \to Z, there is a function F(f) \colon F(Y) \to F(Z). In other words, F is a functor from \mathsf{C}\to \mathsf{Set}, or a \mathsf{C}-set, if you will.
So the “shape” of the information about all of the morphisms out of an object in \mathsf{C} is a \mathsf{C}-set.
Take the category \mathsf{Petri} presented by the following diagram
Then let F be the \mathsf{Petri}-set of morphisms out of S. F(S) = \{ \operatorname{id}_{S} \}, and F(x) = \emptyset for x \in \{S,I,O\}. Interpreted as a Petri net, F is the single-species Petri net.
Now let F be the \mathsf{Petri}-set of morphisms out of I. Then F(S) = \{ \mathrm{is} \}, F(T) = \{\mathrm{it}\}, F(I) = \{ \operatorname{id}_{I} \}. Interpreted as a Petri net, F has a single species, a single transition, and one arc going from the species to the transition.
We summarize what we’ve talked about so far in the following proposition.
Given a category \mathsf{C} and an object X \in \mathsf{C}, there is a \mathsf{C}-set y_{\mathsf{C}}(X) \colon \mathsf{C}\to \mathsf{Set}, such that y_{\mathsf{C}}(X)(Y) = \operatorname{Hom}_{\mathsf{C}}(X,Y).
We call y_{\mathsf{C}}(X) the “representable functor at X”. We’re now going to talk about how to compute these representable functors in a special case.
Suppose that \mathsf{C} is the path graph category for a graph G, so that an object of \mathsf{C} is a vertex of G, and a morphism of \mathsf{C} is a path in G.
Our goal is to be able to fix a \in \mathsf{C}, and then compute \operatorname{Hom}_{\mathsf{C}}(a,b) for every b. Of course, if there are loops in G, then \operatorname{Hom}_{\mathsf{C}}(a,b) could be infinite, so we’re going to assume that G is a directed acyclic graph.
This is going to be kind of like Dijkstra’s algorithm, which computes the shortest path between different vertices, except instead of computing the shortest path, we’re going to compute the set of all paths. But we’re going to use a similar trick of expanding the problem to be computing all the paths between all pairs of vertices.
For this problem, we’re going to use Catlab, because Catlab has some nice features for printing out graphs that I don’t want to recreate.
using Pkg; Pkg.activate(".")
using Catlab
using Catlab.Graphs
= path_graph(Graph, 10) g
E | src | tgt |
---|---|---|
1 | 1 | 2 |
2 | 2 | 3 |
3 | 3 | 4 |
4 | 4 | 5 |
5 | 5 | 6 |
6 | 6 | 7 |
7 | 7 | 8 |
8 | 8 | 9 |
9 | 9 | 10 |
using Catlab.Graphics
to_graphviz(g)
We will represent a path in a graph as a vector of edge ids.
const Path = Vector{Int}
Then we will write a function
function compute_paths(g::Graph)::Matrix{Set{Path}}
...
end
which returns an n \times n matrix P, where n is the number of vertices in the graph, P_{v,w} is the set of paths from v to w.
function compute_paths(g::Graph)
= nv(g) # the number of vertices in g
n = [Set{Path}() for _ in 1:n, _ in 1:n]
P
# add all of the identity paths
for v in vertices(g)
push!(P[v,v], Int[])
end
# at each iteration, we find the paths of length k
# the longest paths are length n
for k in 1:n
for e in edges(g)
= src(g,e), tgt(g,e)
s,t for v in vertices(g)
for p in P[v,s]
if length(p) == k - 1
push!(P[v,t], [p; e])
end
end
end
end
end
Pend
compute_paths(g)
10×10 Matrix{Set{Vector{Int64}}}:
Set([[]]) Set([[1]]) Set([[1, 2]]) … Set([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
Set() Set([[]]) Set([[2]]) Set([[2, 3, 4, 5, 6, 7, 8, 9]])
Set() Set() Set([[]]) Set([[3, 4, 5, 6, 7, 8, 9]])
Set() Set() Set() Set([[4, 5, 6, 7, 8, 9]])
Set() Set() Set() Set([[5, 6, 7, 8, 9]])
Set() Set() Set() … Set([[6, 7, 8, 9]])
Set() Set() Set() Set([[7, 8, 9]])
Set() Set() Set() Set([[8, 9]])
Set() Set() Set() Set([[9]])
Set() Set() Set() Set([[]])
Now, let’s think about what this is saying mathematically. Let G be the path graph with 10 vertices, and let \mathsf{C} be the path category on G. \mathsf{C} has objects 1,\ldots,10, one morphism from i to j if i \leq j, and zero morphisms if i > j. Thus the representable y_{\mathsf{C}}(i) is given by
y_{\mathsf{C}}(i)(j) = \begin{cases} 1 & \text{if $i \leq j$} \\ \emptyset & \text{otherwise} \end{cases}
Note that it’s possible to have a function from \emptyset to 1, but not the other way around. So if there’s a morphism from x to y, and F(x) is non-empty, then F(y) has to also be non-empty.
This also implies that there can’t be an isomorphism between y_{\mathsf{C}}(i) and y_{\mathsf{C}}(j) for i \neq j, because if i < j then y_{\mathsf{C}}(i)(i) is non-empty but y_{\mathsf{C}}(j)(i) is empty.
This is a specific instance of the general phenomenon that looking at all of the morphisms out of an object characterizes that object.
Previously, we have gone from objects of \mathsf{C} to \mathsf{C}-sets, taking x \in \mathsf{C} to y_\mathsf{C}(x). But we can also ask the question, given an arbitrary F \colon \mathsf{C}\to \mathsf{Set}, is there an x \in \mathsf{C} such that y_\mathsf{C}(x) \cong F? We ask this question by saying “does F have a representative?”
Suppose you come back from a party, and you had a really good time talking to someone but you can’t remember their name. But you do remember the conversations that the person had with the other people at the party. So you call up a friend, and you ask “who was that person who was had 3 conversations with Alice, 2 conversations with Bob, and didn’t talk to Eve at all?” Your friend might say “oh, that was Roberta”, or might say “you must have been drunk; nobody had that sequence of conversations.”
Of course, there might be several people of that description, and no two people are really “isomorphic”, but the basic idea is still there. You can generally identify someone by how they relate to other people. Finding a representing object for a \mathsf{C}-set is conceptually the same process; the \mathsf{C}-set is the description of how the object relates to other objects.
Consider the functor U from \mathsf{Vect} to \mathsf{Set} which sends a vector space V to its underlying set, and a linear map f \colon V \to W to its underlying function. Think for a second, is there a representing object for this functor?
Yes: one representing object for this functor is the vector space \mathbb{R}. What does this mean precisely? This means that there is an natural isomorphism between the functors y_{\mathsf{Vect}}(\mathbb{R}) and U. That is, for every vector space V, there is an isomorphism between the set y_{\mathsf{Vect}}(\mathbb{R})(V) = \operatorname{Hom}_{\mathsf{Vect}}(\mathbb{R},V) and the set V.
We construct this isomorphism in the following way. Given a linear map f \colon \mathbb{R}\to V, there is a corresponding element f(1) \in V, and given an element v \in V, there is a unique linear map f \colon \mathbb{R}\to V such that f(1) = v. Let \alpha_{V} \colon y_{\mathsf{Vect}}(\mathbb{R})(V) \to U(V) and \alpha_{V}^{-1} \colon U(V) \to y_{\mathsf{Vect}}(\mathbb{R})(V) be these maps.
We then need to also check the naturality toblerone for \alpha. We won’t do this every time, but it’s good practice.
Let V and W be vector spaces, and let g \colon U \to V be a map between them. Then the bottom of the naturality toblerone for g is
Remember that the action of y_{\mathsf{Vect}}(\mathbb{R}) on morphisms is composition. So if we start out with f \colon \mathbb{R}\to V, and take the left-bottom route, we first get g \circ f \in y_{\mathsf{Vect}}(\mathbb{R})(W), and then get (g \circ f)(1) \in U(W). If we take the top-right route, we first get f(1) \in U(V), and then get g(f(1)) \in U(W)). As (g \circ f)(1) = g(f(1)), the square commutes! So \alpha is a natural transformation. We can similarly prove that \alpha^{-1} is a natural transformation, and it is clear that \alpha and \alpha^{-1} are inverses, so U and y_{\mathsf{Vect}}(\mathbb{R}) are naturally isomorphic, as required.
Consider the functor F from \mathsf{Vect} to \mathsf{Set} which sends every vector space to the singleton set 1. Is there a representing object for this functor?
Yes, the representing object for this functor is the vector space \mathbb{R}^{0}, because there is precisely one linear map \mathbb{R}^{0} \to V for any vector space V.
Consider the poset (\mathbb{Q}_{\geq 0}, \leq) as a category. Then define F \colon \mathbb{Q}_{\geq 0} \to \mathsf{Set} by
F(x) = \begin{cases} 1 & \text{if $2 \leq x^{2}$} \\ \emptyset & \text{otherwise} \end{cases}
You can check that if x \leq x', then F(x') = \emptyset if and only if F(x) = \emptyset, so we can make F into a functor by supplying the unique functions \emptyset \to 1 and 1 \to 1 for F(x) \to F(x'); we never have to make a function 1 \to \emptyset, which would be impossible.
A representative for F would be a rational number q \geq 0 such that 2 \leq x^{2} if and only if q \leq x. One canditate for this would be \sqrt{2}, but \sqrt{2} isn’t rational! It turns out that no such q exists, so there is no representative for F!
However, if we consider a similar situation with the poset (\mathbb{R}_{\geq 0}, \leq) instead, then F would be representable!
So we see that representability has many surprising and non-trivial applications.