| Copyright | (c) Andrey Mokhov 2016-2018 |
|---|---|
| License | MIT (see the file LICENSE) |
| Maintainer | andrey.mokhov@gmail.com |
| Stability | experimental |
| Safe Haskell | None |
| Language | Haskell2010 |
Algebra.Graph.Fold
Contents
Description
Alga is a library for algebraic construction and manipulation of graphs in Haskell. See this paper for the motivation behind the library, the underlying theory, and implementation details.
This module defines the Fold data type -- the Boehm-Berarducci encoding of
algebraic graphs, which is used for generalised graph folding and for the
implementation of polymorphic graph construction and transformation algorithms.
Fold is an instance of type classes defined in modules Algebra.Graph.Class
and Algebra.Graph.HigherKinded.Class, which can be used for polymorphic
graph construction and manipulation.
- data Fold a
- empty :: Graph g => g
- vertex :: Graph g => Vertex g -> g
- edge :: Graph g => Vertex g -> Vertex g -> g
- overlay :: Graph g => g -> g -> g
- connect :: Graph g => g -> g -> g
- vertices :: Graph g => [Vertex g] -> g
- edges :: Graph g => [(Vertex g, Vertex g)] -> g
- overlays :: Graph g => [g] -> g
- connects :: Graph g => [g] -> g
- foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Fold a -> b
- isSubgraphOf :: (Graph g, Eq g) => g -> g -> Bool
- isEmpty :: Fold a -> Bool
- size :: Fold a -> Int
- hasVertex :: Eq a => a -> Fold a -> Bool
- hasEdge :: Ord a => a -> a -> Fold a -> Bool
- vertexCount :: Ord a => Fold a -> Int
- edgeCount :: Ord a => Fold a -> Int
- vertexList :: Ord a => Fold a -> [a]
- edgeList :: Ord a => Fold a -> [(a, a)]
- vertexSet :: Ord a => Fold a -> Set a
- vertexIntSet :: Fold Int -> IntSet
- edgeSet :: Ord a => Fold a -> Set (a, a)
- path :: Graph g => [Vertex g] -> g
- circuit :: Graph g => [Vertex g] -> g
- clique :: Graph g => [Vertex g] -> g
- biclique :: Graph g => [Vertex g] -> [Vertex g] -> g
- star :: Graph g => Vertex g -> [Vertex g] -> g
- starTranspose :: Graph g => Vertex g -> [Vertex g] -> g
- tree :: Graph g => Tree (Vertex g) -> g
- forest :: Graph g => Forest (Vertex g) -> g
- mesh :: (Graph g, Vertex g ~ (a, b)) => [a] -> [b] -> g
- torus :: (Graph g, Vertex g ~ (a, b)) => [a] -> [b] -> g
- deBruijn :: (Graph g, Vertex g ~ [a]) => Int -> [a] -> g
- removeVertex :: (Eq (Vertex g), Graph g) => Vertex g -> Fold (Vertex g) -> g
- removeEdge :: (Eq (Vertex g), Graph g) => Vertex g -> Vertex g -> Fold (Vertex g) -> g
- replaceVertex :: (Eq (Vertex g), Graph g) => Vertex g -> Vertex g -> Fold (Vertex g) -> g
- mergeVertices :: Graph g => (Vertex g -> Bool) -> Vertex g -> Fold (Vertex g) -> g
- splitVertex :: (Eq (Vertex g), Graph g) => Vertex g -> [Vertex g] -> Fold (Vertex g) -> g
- transpose :: Graph g => Fold (Vertex g) -> g
- gmap :: Graph g => (a -> Vertex g) -> Fold a -> g
- bind :: Graph g => Fold a -> (a -> g) -> g
- induce :: Graph g => (Vertex g -> Bool) -> Fold (Vertex g) -> g
- simplify :: (Eq g, Graph g) => Fold (Vertex g) -> g
- box :: (Graph g, Vertex g ~ (a, b)) => Fold a -> Fold b -> g
Boehm-Berarducci encoding of algebraic graphs
The Fold data type is the Boehm-Berarducci encoding of the core graph
construction primitives empty, vertex, overlay and connect. We define a
Num instance as a convenient notation for working with graphs:
0 == vertex 0 1 + 2 == overlay (vertex 1) (vertex 2) 1 * 2 == connect (vertex 1) (vertex 2) 1 + 2 * 3 == overlay (vertex 1) (connect (vertex 2) (vertex 3)) 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3))
The Show instance is defined using basic graph construction primitives:
show (empty :: Fold Int) == "empty" show (1 :: Fold Int) == "vertex 1" show (1 + 2 :: Fold Int) == "vertices [1,2]" show (1 * 2 :: Fold Int) == "edge 1 2" show (1 * 2 * 3 :: Fold Int) == "edges [(1,2),(1,3),(2,3)]" show (1 * 2 + 3 :: Fold Int) == "overlay (vertex 3) (edge 1 2)"
The Eq instance is currently implemented using the AdjacencyMap as the
canonical graph representation and satisfies all axioms of algebraic graphs:
overlayis commutative and associative:x + y == y + x x + (y + z) == (x + y) + z
connectis associative and hasemptyas the identity:x * empty == x empty * x == x x * (y * z) == (x * y) * z
connectdistributes overoverlay:x * (y + z) == x * y + x * z (x + y) * z == x * z + y * z
connectcan be decomposed:x * y * z == x * y + x * z + y * z
The following useful theorems can be proved from the above set of axioms.
overlayhasemptyas the identity and is idempotent:x + empty == x empty + x == x x + x == xAbsorption and saturation of
connect:x * y + x + y == x * y x * x * x == x * x
When specifying the time and memory complexity of graph algorithms, n will
denote the number of vertices in the graph, m will denote the number of
edges in the graph, and s will denote the size of the corresponding
graph expression. For example, if g is a Fold then n, m and s can be
computed as follows:
n ==vertexCountg m ==edgeCountg s ==sizeg
Note that size is slightly different from the length method of the
Foldable type class, as the latter does not count empty leaves of the
expression:
lengthempty== 0sizeempty== 1length(vertexx) == 1size(vertexx) == 1length(empty+empty) == 0size(empty+empty) == 2
The size of any graph is positive, and the difference (
corresponds to the number of occurrences of size g - length g)empty in an expression g.
Converting a Fold to the corresponding AdjacencyMap takes O(s + m * log(m))
time and O(s + m) memory. This is also the complexity of the graph equality test,
because it is currently implemented by converting graph expressions to canonical
representations based on adjacency maps.
Instances
| Monad Fold Source # | |
| Functor Fold Source # | |
| Applicative Fold Source # | |
| Foldable Fold Source # | |
| Traversable Fold Source # | |
| Alternative Fold Source # | |
| MonadPlus Fold Source # | |
| ToGraph Fold Source # | |
| Graph Fold Source # | |
| Ord a => Eq (Fold a) Source # | |
| Num a => Num (Fold a) Source # | |
| (Ord a, Show a) => Show (Fold a) Source # | |
| ToGraph (Fold a) Source # | |
| Graph (Fold a) Source # | |
| type ToVertex (Fold a) Source # | |
| type Vertex (Fold a) Source # | |
Basic graph construction primitives
empty :: Graph g => g Source #
Construct the empty graph. Complexity: O(1) time, memory and size.
isEmptyempty == TruehasVertexx empty == FalsevertexCountempty == 0edgeCountempty == 0sizeempty == 1
vertex :: Graph g => Vertex g -> g Source #
Construct the graph comprising a single isolated vertex. Complexity: O(1) time, memory and size.
isEmpty(vertex x) == FalsehasVertexx (vertex x) == TruevertexCount(vertex x) == 1edgeCount(vertex x) == 0size(vertex x) == 1
edge :: Graph g => Vertex g -> Vertex g -> g Source #
Construct the graph comprising a single edge. Complexity: O(1) time, memory and size.
edge x y ==connect(vertexx) (vertexy)hasEdgex y (edge x y) == TrueedgeCount(edge x y) == 1vertexCount(edge 1 1) == 1vertexCount(edge 1 2) == 2
overlay :: Graph g => g -> g -> g Source #
Overlay two graphs. This is a commutative, associative and idempotent
operation with the identity empty.
Complexity: O(1) time and memory, O(s1 + s2) size.
isEmpty(overlay x y) ==isEmptyx &&isEmptyyhasVertexz (overlay x y) ==hasVertexz x ||hasVertexz yvertexCount(overlay x y) >=vertexCountxvertexCount(overlay x y) <=vertexCountx +vertexCountyedgeCount(overlay x y) >=edgeCountxedgeCount(overlay x y) <=edgeCountx +edgeCountysize(overlay x y) ==sizex +sizeyvertexCount(overlay 1 2) == 2edgeCount(overlay 1 2) == 0
connect :: Graph g => g -> g -> g Source #
Connect two graphs. This is an associative operation with the identity
empty, which distributes over overlay and obeys the decomposition axiom.
Complexity: O(1) time and memory, O(s1 + s2) size. Note that the number
of edges in the resulting graph is quadratic with respect to the number of
vertices of the arguments: m = O(m1 + m2 + n1 * n2).
isEmpty(connect x y) ==isEmptyx &&isEmptyyhasVertexz (connect x y) ==hasVertexz x ||hasVertexz yvertexCount(connect x y) >=vertexCountxvertexCount(connect x y) <=vertexCountx +vertexCountyedgeCount(connect x y) >=edgeCountxedgeCount(connect x y) >=edgeCountyedgeCount(connect x y) >=vertexCountx *vertexCountyedgeCount(connect x y) <=vertexCountx *vertexCounty +edgeCountx +edgeCountysize(connect x y) ==sizex +sizeyvertexCount(connect 1 2) == 2edgeCount(connect 1 2) == 1
vertices :: Graph g => [Vertex g] -> g Source #
Construct the graph comprising a given list of isolated vertices. Complexity: O(L) time, memory and size, where L is the length of the given list.
vertices [] ==emptyvertices [x] ==vertexxhasVertexx . vertices ==elemxvertexCount. vertices ==length.nubvertexSet. vertices == Set.fromList
overlays :: Graph g => [g] -> g Source #
Overlay a given list of graphs. Complexity: O(L) time and memory, and O(S) size, where L is the length of the given list, and S is the sum of sizes of the graphs in the list.
overlays [] ==emptyoverlays [x] == x overlays [x,y] ==overlayx y overlays ==foldroverlayemptyisEmpty. overlays ==allisEmpty
connects :: Graph g => [g] -> g Source #
Connect a given list of graphs. Complexity: O(L) time and memory, and O(S) size, where L is the length of the given list, and S is the sum of sizes of the graphs in the list.
connects [] ==emptyconnects [x] == x connects [x,y] ==connectx y connects ==foldrconnectemptyisEmpty. connects ==allisEmpty
Graph folding
foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Fold a -> b Source #
Generalised graph folding: recursively collapse a Fold by applying
the provided functions to the leaves and internal nodes of the expression.
The order of arguments is: empty, vertex, overlay and connect.
Complexity: O(s) applications of given functions. As an example, the
complexity of size is O(s), since all functions have cost O(1).
foldgemptyvertexoverlayconnect== id foldgemptyvertexoverlay(flipconnect) ==transposefoldg [] return (++) (++) ==toListfoldg 0 (const 1) (+) (+) ==lengthfoldg 1 (const 1) (+) (+) ==sizefoldg True (const False) (&&) (&&) ==isEmpty
Relations on graphs
isSubgraphOf :: (Graph g, Eq g) => g -> g -> Bool Source #
The isSubgraphOf function takes two graphs and returns True if the
first graph is a subgraph of the second. Here is the current implementation:
isSubgraphOf x y = overlay x y == y
The complexity therefore depends on the complexity of equality testing of the specific graph instance.
isSubgraphOfemptyx == True isSubgraphOf (vertexx)empty== False isSubgraphOf x (overlayx y) == True isSubgraphOf (overlayx y) (connectx y) == True isSubgraphOf (pathxs) (circuitxs) == True
Graph properties
isEmpty :: Fold a -> Bool Source #
Check if a graph is empty. A convenient alias for null.
Complexity: O(s) time.
isEmptyempty== True isEmpty (overlayemptyempty) == True isEmpty (vertexx) == False isEmpty (removeVertexx $vertexx) == True isEmpty (removeEdgex y $edgex y) == False
hasVertex :: Eq a => a -> Fold a -> Bool Source #
Check if a graph contains a given vertex. A convenient alias for elem.
Complexity: O(s) time.
hasVertex xempty== False hasVertex x (vertexx) == True hasVertex 1 (vertex2) == False hasVertex x .removeVertexx == const False
vertexCount :: Ord a => Fold a -> Int Source #
The number of vertices in a graph. Complexity: O(s * log(n)) time.
vertexCountempty== 0 vertexCount (vertexx) == 1 vertexCount ==length.vertexList
vertexList :: Ord a => Fold a -> [a] Source #
edgeList :: Ord a => Fold a -> [(a, a)] Source #
The sorted list of edges of a graph. Complexity: O(s + m * log(m)) time and O(m) memory. Note that the number of edges m of a graph can be quadratic with respect to the expression size s.
edgeListempty== [] edgeList (vertexx) == [] edgeList (edgex y) == [(x,y)] edgeList (star2 [3,1]) == [(2,1), (2,3)] edgeList .edges==nub.sortedgeList .transpose==sort. mapswap. edgeList
vertexIntSet :: Fold Int -> IntSet Source #
The set of vertices of a given graph. Like vertexSet but specialised for
graphs with vertices of type Int.
Complexity: O(s * log(n)) time and O(n) memory.
vertexIntSetempty== IntSet.emptyvertexIntSet .vertex== IntSet.singletonvertexIntSet .vertices== IntSet.fromListvertexIntSet .clique== IntSet.fromList
Standard families of graphs
biclique :: Graph g => [Vertex g] -> [Vertex g] -> g Source #
The biclique on two lists of vertices. Complexity: O(L1 + L2) time, memory and size, where L1 and L2 are the lengths of the given lists.
biclique [] [] ==emptybiclique [x] [] ==vertexx biclique [] [y] ==vertexy biclique [x1,x2] [y1,y2] ==edges[(x1,y1), (x1,y2), (x2,y1), (x2,y2)] biclique xs ys ==connect(verticesxs) (verticesys)
starTranspose :: Graph g => Vertex g -> [Vertex g] -> g Source #
The star transpose formed by a list of leaves connected to a centre vertex. Complexity: O(L) time, memory and size, where L is the length of the given list.
starTranspose x [] ==vertexx starTranspose x [y] ==edgey x starTranspose x [y,z] ==edges[(y,x), (z,x)] starTranspose x ys ==connect(verticesys) (vertexx) starTranspose x ys == transpose (starx ys)
tree :: Graph g => Tree (Vertex g) -> g Source #
The tree graph constructed from a given Tree data structure.
Complexity: O(T) time, memory and size, where T is the size of the
given tree (i.e. the number of vertices in the tree).
tree (Node x []) ==vertexx tree (Node x [Node y [Node z []]]) ==path[x,y,z] tree (Node x [Node y [], Node z []]) ==starx [y,z] tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) ==edges[(1,2), (1,3), (3,4), (3,5)]
forest :: Graph g => Forest (Vertex g) -> g Source #
The forest graph constructed from a given Forest data structure.
Complexity: O(F) time, memory and size, where F is the size of the
given forest (i.e. the number of vertices in the forest).
forest [] ==emptyforest [x] ==treex forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] ==edges[(1,2), (1,3), (4,5)] forest ==overlays. maptree
mesh :: (Graph g, Vertex g ~ (a, b)) => [a] -> [b] -> g Source #
Construct a mesh graph from two lists of vertices. Complexity: O(L1 * L2) time, memory and size, where L1 and L2 are the lengths of the given lists.
mesh xs [] ==emptymesh [] ys ==emptymesh [x] [y] ==vertex(x, y) mesh xs ys ==box(pathxs) (pathys) mesh [1..3] "ab" ==edges[ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(2,'b')), ((2,'a'),(2,'b')) , ((2,'a'),(3,'a')), ((2,'b'),(3,'b')), ((3,'a'),(3,'b')) ]
torus :: (Graph g, Vertex g ~ (a, b)) => [a] -> [b] -> g Source #
Construct a torus graph from two lists of vertices. Complexity: O(L1 * L2) time, memory and size, where L1 and L2 are the lengths of the given lists.
torus xs [] ==emptytorus [] ys ==emptytorus [x] [y] ==edge(x, y) (x, y) torus xs ys ==box(circuitxs) (circuitys) torus [1,2] "ab" ==edges[ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(1,'a')), ((1,'b'),(2,'b')) , ((2,'a'),(1,'a')), ((2,'a'),(2,'b')), ((2,'b'),(1,'b')), ((2,'b'),(2,'a')) ]
deBruijn :: (Graph g, Vertex g ~ [a]) => Int -> [a] -> g Source #
Construct a De Bruijn graph of a given non-negative dimension using symbols from a given alphabet. Complexity: O(A^(D + 1)) time, memory and size, where A is the size of the alphabet and D is the dimension of the graph.
deBruijn 0 xs ==edge[] [] n > 0 ==> deBruijn n [] ==emptydeBruijn 1 [0,1] ==edges[ ([0],[0]), ([0],[1]), ([1],[0]), ([1],[1]) ] deBruijn 2 "0" ==edge"00" "00" deBruijn 2 "01" ==edges[ ("00","00"), ("00","01"), ("01","10"), ("01","11") , ("10","00"), ("10","01"), ("11","10"), ("11","11") ]transpose(deBruijn n xs) ==gmapreverse$ deBruijn n xsvertexCount(deBruijn n xs) == (length$nubxs)^n n > 0 ==>edgeCount(deBruijn n xs) == (length$nubxs)^(n + 1)
Graph transformation
removeEdge :: (Eq (Vertex g), Graph g) => Vertex g -> Vertex g -> Fold (Vertex g) -> g Source #
Remove an edge from a given graph. Complexity: O(s) time, memory and size.
removeEdge x y (edgex y) ==vertices[x, y] removeEdge x y . removeEdge x y == removeEdge x y removeEdge x y .removeVertexx ==removeVertexx removeEdge 1 1 (1 * 1 * 2 * 2) == 1 * 2 * 2 removeEdge 1 2 (1 * 1 * 2 * 2) == 1 * 1 + 2 * 2size(removeEdge x y z) <= 3 *sizez
replaceVertex :: (Eq (Vertex g), Graph g) => Vertex g -> Vertex g -> Fold (Vertex g) -> g Source #
The function replaces vertex replaceVertex x yx with vertex y in a
given graph expression. If y already exists, x and y will be merged.
Complexity: O(s) time, memory and size.
replaceVertex x x == id replaceVertex x y (vertexx) ==vertexy replaceVertex x y ==mergeVertices(== x) y
mergeVertices :: Graph g => (Vertex g -> Bool) -> Vertex g -> Fold (Vertex g) -> g Source #
Merge vertices satisfying a given predicate into a given vertex. Complexity: O(s) time, memory and size, assuming that the predicate takes O(1) to be evaluated.
mergeVertices (const False) x == id
mergeVertices (== x) y == replaceVertex x y
mergeVertices even 1 (0 * 2) == 1 * 1
mergeVertices odd 1 (3 + 4 * 5) == 4 * 1
splitVertex :: (Eq (Vertex g), Graph g) => Vertex g -> [Vertex g] -> Fold (Vertex g) -> g Source #
Split a vertex into a list of vertices with the same connectivity. Complexity: O(s + k * L) time, memory and size, where k is the number of occurrences of the vertex in the expression and L is the length of the given list.
splitVertex x [] ==removeVertexx splitVertex x [x] == id splitVertex x [y] ==replaceVertexx y splitVertex 1 [0,1] $ 1 * (2 + 3) == (0 + 1) * (2 + 3)
bind :: Graph g => Fold a -> (a -> g) -> g Source #
Transform a given graph by substituting each of its vertices with a subgraph.
This is similar to Monad's bind >>= but can be used with non-fully-parametric
graphs.
bindemptyf ==emptybind (vertexx) f == f x bind (edgex y) f ==connect(f x) (f y) bind (verticesxs) f ==overlays(mapf xs) bind x (constempty) ==emptybind xvertex== x bind (bind x f) g == bind x (\y -> bind (f y) g)
induce :: Graph g => (Vertex g -> Bool) -> Fold (Vertex g) -> g Source #
Construct the induced subgraph of a given graph by removing the vertices that do not satisfy a given predicate. Complexity: O(s) time, memory and size, assuming that the predicate takes O(1) to be evaluated.
induce (const True ) x == x induce (const False) x ==emptyinduce (/= x) ==removeVertexx induce p . induce q == induce (\x -> p x && q x)isSubgraphOf(induce p x) x == True
simplify :: (Eq g, Graph g) => Fold (Vertex g) -> g Source #
Simplify a graph expression. Semantically, this is the identity function,
but it simplifies a given polymorphic graph expression according to the laws
of the algebra. The function does not compute the simplest possible expression,
but uses heuristics to obtain useful simplifications in reasonable time.
Complexity: the function performs O(s) graph comparisons. It is guaranteed
that the size of the result does not exceed the size of the given expression.
Below the operator ~> denotes the is simplified to relation.
simplify == idsize(simplify x) <=sizex simplifyempty~>emptysimplify 1 ~> 1 simplify (1 + 1) ~> 1 simplify (1 + 2 + 1) ~> 1 + 2 simplify (1 * 1 * 1) ~> 1 * 1
Graph composition
box :: (Graph g, Vertex g ~ (a, b)) => Fold a -> Fold b -> g Source #
Compute the Cartesian product of graphs. Complexity: O(s1 * s2) time, memory and size, where s1 and s2 are the sizes of the given graphs.
box (path[0,1]) (path"ab") ==edges[ ((0,'a'), (0,'b')) , ((0,'a'), (1,'a')) , ((0,'b'), (1,'b')) , ((1,'a'), (1,'b')) ]
Up to an isomorphism between the resulting vertex types, this operation
is commutative, associative, distributes over overlay, has singleton
graphs as identities and empty as the annihilating zero. Below ~~
stands for the equality up to an isomorphism, e.g. (x, ()) ~~ x.
box x y ~~ box y x box x (box y z) ~~ box (box x y) z box x (overlayy z) ==overlay(box x y) (box x z) box x (vertex()) ~~ x box xempty~~emptytranspose(box x y) == box (transposex) (transposey)vertexCount(box x y) ==vertexCountx *vertexCountyedgeCount(box x y) <=vertexCountx *edgeCounty +edgeCountx *vertexCounty