A directed graph (or digraph) is an ordered pair , where
is a non-empty finite set of elements called vertices, and
is a finite set of elements called arcs, where an arc is an ordered pair of distinct vertices [1]. We call
and
the vertex set and the arc set, respectively. Note that
. For an arc
, we call
the tail, and
the head, and say that the arc
leaves vertex
and enters vertex
.
For instance, consider the digraph depicted below
This digraph has 10 vertices and 15 arcs. How would we build this digraph in Haskell? A vertex could be represented by an integer, and an arc could be represented by an ordered pair of integers. However, in Mathematics we work with sets, whereas in Haskell we work with lists. Hence, we could represent the vertex set by a list of vertices, and the arc set by a list of edges.
Here is a simplistic implementation:
-- type synonyms
type Vertex = Int
type Arc = (Vertex,Vertex)
type Digraph = ([Vertex],[Arc])
-- create list of vertices
vs :: [Vertex]
vs = [1..10]
-- create list of arcs
as :: [Arc]
as = [(1,4),(1,5),(1,6),(2,4),(3,4),
(4,5),(5,6),(7,6),(8,1),(8,2),
(8,7),(9,8),(9,10),(10,2),(10,3)]
-- create digraph
digraph :: Digraph
digraph = (vs,as)
We load this script in GHCi and perform some simple testing:
*Main> -- list of vertices *Main> vs [1,2,3,4,5,6,7,8,9,10] *Main> length vs 10 *Main> -- list of arcs *Main> as [(1,4),(1,5),(1,6),(2,4),(3,4),(4,5),(5,6),(7,6), (8,1),(8,2),(8,7),(9,8),(9,10),(10,2),(10,3)] *Main> length as 15 *Main> -- digraph *Main> digraph ([1,2,3,4,5,6,7,8,9,10],[(1,4),(1,5),(1,6), (2,4),(3,4),(4,5),(5,6),(7,6),(8,1),(8,2), (8,7),(9,8),(9,10),(10,2),(10,3)])
We have thus created a digraph. What can we do with it? Is there anything of interest that we could compute?
__________
Neighborhoods
Given a digraph , we call the following sets
the out-neighborhood of vertex and the in-neighborhood of vertex
, respectively [1]. The vertices in
and
are called the out-neighbors and the in-neighbors of vertex
, respectively.
In Haskell, we compute the out- and in-neighborhoods as follows:
-- compute out-neighborbood of a vertex
outNeighbors :: Digraph -> Vertex -> [Vertex]
outNeighbors (vs,as) v = map snd (filter (p v) as)
where p v (t,h) | t == v = True
| t /= v = False
-- compute in-neighborbood of a vertex
inNeighbors :: Digraph -> Vertex -> [Vertex]
inNeighbors (vs,as) v = map fst (filter (p v) as)
where p v (t,h) | h == v = True
| h /= v = False
Let us do some testing in GHCi:
*Main> -- list of all out-neighborhoods *Main> map (outNeighbors digraph) vs [[4,5,6],[4],[4],[5],[6],[],[6],[1,2,7],[8,10],[2,3]] *Main> -- list of all in-neighborhoods *Main> map (inNeighbors digraph) vs [[8],[8,10],[10],[1,2,3],[1,4],[1,5,7],[8],[9],[],[9]]
__________
Degrees
Given a digraph , we call the following cardinalities
the out-degree and the in-degree of vertex , respectively [1]. We compute the out- and in-degrees in Haskell as follows:
-- compute out-degree of a vertex outDegree :: Digraph -> Vertex -> Int outDegree (vs,as) v = length (outNeighbors (vs,as) v) -- compute in-degree of a vertex inDegree :: Digraph -> Vertex -> Int inDegree (vs,as) v = length (inNeighbors (vs,as) v)
Let us do some testing in GHCi:
*Main> -- out-degrees of all vertices *Main> map (outDegree digraph) vs [3,1,1,1,1,0,1,3,2,2] *Main> -- in-degrees of all vertices *Main> map (inDegree digraph) vs [1,2,1,3,2,3,1,1,0,1]
__________
Concluding remarks
Here is the whole Haskell script:
-- type synonyms
type Vertex = Int
type Arc = (Vertex,Vertex)
type Digraph = ([Vertex],[Arc])
-- create list of vertices
vs :: [Vertex]
vs = [1..10]
-- create list of arcs
as :: [Arc]
as = [(1,4),(1,5),(1,6),(2,4),(3,4),
(4,5),(5,6),(7,6),(8,1),(8,2),
(8,7),(9,8),(9,10),(10,2),(10,3)]
-- create digraph
digraph :: Digraph
digraph = (vs,as)
-- compute out-neighborbood of a vertex
outNeighbors :: Digraph -> Vertex -> [Vertex]
outNeighbors (vs,as) v = map snd (filter (p v) as)
where p v (t,h) | t == v = True
| t /= v = False
-- compute in-neighborbood of a vertex
inNeighbors :: Digraph -> Vertex -> [Vertex]
inNeighbors (vs,as) v = map fst (filter (p v) as)
where p v (t,h) | h == v = True
| h /= v = False
-- compute out-degree of a vertex
outDegree :: Digraph -> Vertex -> Int
outDegree (vs,as) v = length (outNeighbors (vs,as) v)
-- compute in-degree of a vertex
inDegree :: Digraph -> Vertex -> Int
inDegree (vs,as) v = length (inNeighbors (vs,as) v)
We now know how to create digraphs in Haskell and compute simple things, like neighborhoods and degrees. What else would it be of interest to compute?
__________
References
[1] Jørgen Bang-Jensen, Gregory Z. Gutin, Digraphs: Theory, Algorithms and Applications (2nd edition), Springer, 2009.
