| Copyright | (c) Andrey Mokhov 2016-2022 |
|---|---|
| License | MIT (see the file LICENSE) |
| Maintainer | andrey.mokhov@gmail.com |
| Stability | experimental |
| Safe Haskell | None |
| Language | Haskell2010 |
Algebra.Graph.Undirected
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 an undirected version of algebraic graphs. Undirected
graphs satisfy all laws of the Undirected type class,
including the commutativity of connect.
To avoid name clashes with Algebra.Graph, this module can be imported qualified:
import qualified Algebra.Graph.Undirected as Undirected
Synopsis
- data Graph a
- fromUndirected :: Ord a => Graph a -> Graph a
- toUndirected :: Graph a -> Graph a
- empty :: Graph a
- vertex :: a -> Graph a
- edge :: a -> a -> Graph a
- overlay :: Graph a -> Graph a -> Graph a
- connect :: Graph a -> Graph a -> Graph a
- vertices :: [a] -> Graph a
- edges :: [(a, a)] -> Graph a
- overlays :: [Graph a] -> Graph a
- connects :: [Graph a] -> Graph a
- foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b
- isSubgraphOf :: Ord a => Graph a -> Graph a -> Bool
- toRelation :: Ord a => Graph a -> Relation a
- isEmpty :: Graph a -> Bool
- size :: Graph a -> Int
- hasVertex :: Eq a => a -> Graph a -> Bool
- hasEdge :: Eq a => a -> a -> Graph a -> Bool
- vertexCount :: Ord a => Graph a -> Int
- edgeCount :: Ord a => Graph a -> Int
- vertexList :: Ord a => Graph a -> [a]
- edgeList :: Ord a => Graph a -> [(a, a)]
- vertexSet :: Ord a => Graph a -> Set a
- edgeSet :: Ord a => Graph a -> Set (a, a)
- adjacencyList :: Ord a => Graph a -> [(a, [a])]
- neighbours :: Ord a => a -> Graph a -> Set a
- path :: [a] -> Graph a
- circuit :: [a] -> Graph a
- clique :: [a] -> Graph a
- biclique :: [a] -> [a] -> Graph a
- star :: a -> [a] -> Graph a
- stars :: [(a, [a])] -> Graph a
- tree :: Tree a -> Graph a
- forest :: Forest a -> Graph a
- removeVertex :: Eq a => a -> Graph a -> Graph a
- removeEdge :: Eq a => a -> a -> Graph a -> Graph a
- replaceVertex :: Eq a => a -> a -> Graph a -> Graph a
- mergeVertices :: (a -> Bool) -> a -> Graph a -> Graph a
- induce :: (a -> Bool) -> Graph a -> Graph a
- induceJust :: Graph (Maybe a) -> Graph a
- complement :: Ord a => Graph a -> Graph a
Algebraic data type for graphs
The Graph data type provides the four algebraic graph construction
primitives empty, vertex, overlay and connect, as well as various
derived functions. The only difference compared to the Graph
data type defined in Algebra.Graph is that the connect operation is
commutative. We define a Num instance as a convenient notation for working
with undirected graphs:
0 ==vertex0 1 + 2 ==overlay(vertex1) (vertex2) 1 * 2 ==connect(vertex1) (vertex2) 1 + 2 * 3 ==overlay(vertex1) (connect(vertex2) (vertex3)) 1 * (2 + 3) ==connect(vertex1) (overlay(vertex2) (vertex3))
Note: the Num instance does not satisfy several "customary laws" of Num,
which dictate that fromInteger 0 and fromInteger 1 should act as
additive and multiplicative identities, and negate as additive inverse.
Nevertheless, overloading fromInteger, + and * is very convenient when
working with algebraic graphs; we hope that in future Haskell's Prelude will
provide a more fine-grained class hierarchy for algebraic structures, which we
would be able to utilise without violating any laws.
The Eq instance is currently implemented using the Relation 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, commutative and hasemptyas the identity:x * empty == x empty * x == x x * y == y * x x * (y * z) == (x * y) * zconnectdistributes 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 Graph then n, m and s can be
computed as follows:
n ==vertexCountg m ==edgeCountg s ==sizeg
Note that size counts all leaves of the expression:
vertexCountempty== 0sizeempty== 1vertexCount(vertexx) == 1size(vertexx) == 1vertexCount(empty+empty) == 0size(empty+empty) == 2
Converting an undirected Graph to the corresponding Relation 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.
The total order on graphs is defined using size-lexicographic comparison:
- Compare the number of vertices. In case of a tie, continue.
- Compare the sets of vertices. In case of a tie, continue.
- Compare the number of edges. In case of a tie, continue.
- Compare the sets of edges.
Here are a few examples:
vertex1 <vertex2vertex3 <edge1 2vertex1 <edge1 1edge1 1 <edge1 2edge1 2 <edge1 1 +edge2 2edge1 2 <edge1 3edge1 2 ==edge2 1
Note that the resulting order refines the isSubgraphOf relation and is
compatible with overlay and connect operations:
isSubgraphOf x y ==> x <= yempty <= x
x <= x + y
x + y <= x * yInstances
| Monad Graph Source # | |
| Functor Graph Source # | |
| Applicative Graph Source # | |
| Alternative Graph Source # | |
| MonadPlus Graph Source # | |
| Ord a => Eq (Graph a) Source # | |
| Num a => Num (Graph a) Source # | Note: this does not satisfy the usual ring laws; see |
| Ord a => Ord (Graph a) Source # | |
Defined in Algebra.Graph.Undirected | |
| (Show a, Ord a) => Show (Graph a) Source # | |
| IsString a => IsString (Graph a) Source # | |
Defined in Algebra.Graph.Undirected Methods fromString :: String -> Graph a # | |
| Generic (Graph a) Source # | |
| Semigroup (Graph a) Source # | Defined via |
| Monoid (Graph a) Source # | |
| NFData a => NFData (Graph a) Source # | |
Defined in Algebra.Graph.Undirected | |
| Undirected (Graph a) Source # | |
Defined in Algebra.Graph.Class | |
| Graph (Graph a) Source # | |
| type Rep (Graph a) Source # | |
Defined in Algebra.Graph.Undirected | |
| type Vertex (Graph a) Source # | |
Defined in Algebra.Graph.Class | |
fromUndirected :: Ord a => Graph a -> Graph a Source #
Extract the underlying Algebra.Graph. Complexity: O(n + m) time.
fromUndirected (edge1 2) ==edges[(1,2),(2,1)]toUndirected.fromUndirected== idvertexCount. fromUndirected ==vertexCountedgeCount. fromUndirected <= (*2) .edgeCount
toUndirected :: Graph a -> Graph a Source #
Construct an undirected graph from a given Algebra.Graph. Complexity: O(1) time.
toUndirected (edge1 2) ==edge1 2 toUndirected .fromUndirected== idvertexCount. toUndirected ==vertexCount(*2) .edgeCount. toUndirected >=edgeCount
Basic graph construction primitives
Construct the empty graph.
isEmptyempty == TruehasVertexx empty == FalsevertexCountempty == 0edgeCountempty == 0sizeempty == 1
vertex :: a -> Graph a Source #
Construct the graph comprising a single isolated vertex.
isEmpty(vertex x) == FalsehasVertexx (vertex y) == (x == y)vertexCount(vertex x) == 1edgeCount(vertex x) == 0size(vertex x) == 1
edge :: a -> a -> Graph a Source #
Construct the graph comprising a single edge.
edge x y ==connect(vertexx) (vertexy) edge x y ==edgey x edge x y ==edges[(x,y), (y,x)]hasEdgex y (edge x y) == TrueedgeCount(edge x y) == 1vertexCount(edge 1 1) == 1vertexCount(edge 1 2) == 2
overlay :: Graph a -> Graph a -> Graph a 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 a -> Graph a -> Graph a Source #
Connect two graphs. This is a commutative and 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).
connectx y ==connecty xisEmpty(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 *vertexCountydiv2size(connect x y) ==sizex +sizeyvertexCount(connect 1 2) == 2edgeCount(connect 1 2) == 1
vertices :: [a] -> Graph a 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] ==vertexx vertices ==overlays. mapvertexhasVertexx . vertices ==elemxvertexCount. vertices ==length.nubvertexSet. vertices == Set .fromList
overlays :: [Graph a] -> Graph a 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 a] -> Graph a 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 ==allisEmptyconnects == connects .reverse
Graph folding
foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b Source #
Generalised Graph folding: recursively collapse a Graph 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 the given functions. As an example, the
complexity of size is O(s), since const and + have constant costs.
foldgemptyvertexoverlayconnect== id foldgemptyvertexoverlay(flipconnect) == id foldg 1 (const1) (+) (+) ==sizefoldg True (constFalse) (&&) (&&) ==isEmptyfoldg False (== x) (||) (||) ==hasVertexx
Relations on graphs
isSubgraphOf :: Ord a => Graph a -> Graph a -> Bool Source #
The isSubgraphOf function takes two graphs and returns True if the
first graph is a subgraph of the second.
Complexity: O(s + m * log(m)) time. Note that the number of edges m of a
graph can be quadratic with respect to the expression size s.
isSubgraphOfemptyx == True isSubgraphOf (vertexx)empty== False isSubgraphOf x (overlayx y) == True isSubgraphOf (overlayx y) (connectx y) == True isSubgraphOf (pathxs) (circuitxs) == True isSubgraphOf (edgex y) (edgey x) == True isSubgraphOf x y ==> x <= y
toRelation :: Ord a => Graph a -> Relation a Source #
Convert an undirected graph to a symmetric Relation.
Graph properties
isEmpty :: Graph a -> Bool Source #
Check if a graph is empty. 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 -> Graph a -> Bool Source #
Check if a graph contains a given vertex. Complexity: O(s) time.
hasVertex xempty== False hasVertex x (vertexy) == (x == y) hasVertex x .removeVertexx ==constFalse
vertexCount :: Ord a => Graph a -> Int Source #
The number of vertices in a graph. Complexity: O(s * log(n)) time.
vertexCountempty== 0 vertexCount (vertexx) == 1 vertexCount ==length.vertexListvertexCount x < vertexCount y ==> x < y
vertexList :: Ord a => Graph a -> [a] Source #
edgeList :: Ord a => Graph 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) == [(min x y, max y x)] edgeList (star2 [3,1]) == [(1,2), (2,3)]
adjacencyList :: Ord a => Graph a -> [(a, [a])] Source #
Standard families of graphs
clique :: [a] -> Graph a Source #
The clique on a list of vertices. Complexity: O(L) time, memory and size, where L is the length of the given list.
clique [] ==emptyclique [x] ==vertexx clique [x,y] ==edgex y clique [x,y,z] ==edges[(x,y), (x,z), (y,z)] clique (xs ++ ys) ==connect(clique xs) (clique ys) clique .reverse== clique
biclique :: [a] -> [a] -> Graph a 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,x2), (x2,y2)] biclique xs ys ==connect(verticesxs) (verticesys)
stars :: [(a, [a])] -> Graph a Source #
The stars formed by overlaying a list of stars. An inverse of
adjacencyList.
Complexity: O(L) time, memory and size, where L is the total size of the
input.
stars [] ==emptystars [(x, [])] ==vertexx stars [(x, [y])] ==edgex y stars [(x, ys)] ==starx ys stars ==overlays.map(uncurrystar) stars .adjacencyList== idoverlay(stars xs) (stars ys) == stars (xs ++ ys)
tree :: Tree a -> Graph a 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 :: Forest a -> Graph a 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
Graph transformation
removeEdge :: Eq a => a -> a -> Graph a -> Graph a 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 == removeEdge y x 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 * 2
replaceVertex :: Eq a => a -> a -> Graph a -> Graph a Source #
The function replaces vertex replaceVertex x yx with vertex y in a
given Graph. 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 :: (a -> Bool) -> a -> Graph a -> Graph a Source #
Merge vertices satisfying a given predicate into a given vertex. Complexity: O(s) time, memory and size, assuming that the predicate takes constant time.
mergeVertices (constFalse) x == id mergeVertices (== x) y ==replaceVertexx y mergeVerticeseven1 (0 * 2) == 1 * 1 mergeVerticesodd1 (3 + 4 * 5) == 4 * 1
induce :: (a -> Bool) -> Graph a -> Graph a 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 constant time.
induce (constTrue ) x == x induce (constFalse) x ==emptyinduce (/= x) ==removeVertexx induce p . induce q == induce (\x -> p x && q x)isSubgraphOf(induce p x) x == True
induceJust :: Graph (Maybe a) -> Graph a Source #
Construct the induced subgraph of a given graph by removing the vertices
that are Nothing.
Complexity: O(s) time, memory and size.
induceJust (vertexNothing) ==emptyinduceJust (edge(Justx)Nothing) ==vertexx induceJust .fmapJust==idinduceJust .fmap(\x -> if p x thenJustx elseNothing) ==inducep
complement :: Ord a => Graph a -> Graph a Source #
The edge complement of a graph. Note that, as can be seen from the examples below, this operation ignores self-loops. Complexity: O(n^2 * log n) time, O(n^2) memory.
complementempty==emptycomplement (vertexx) == (vertexx) complement (edge1 2) == (vertices[1, 2]) complement (edge0 0) == (edge0 0) complement (star1 [2, 3]) == (overlay(vertex1) (edge2 3)) complement . complement == id