| Copyright | (c) Andrey Mokhov 2016-2022 |
|---|---|
| License | MIT (see the file LICENSE) |
| Maintainer | [email protected] |
| Stability | experimental |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
Algebra.Graph.Labelled
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 provides a minimal and experimental implementation of algebraic graphs with edge labels. The API will be expanded in the next release.
Synopsis
- data Graph e a
- empty :: Graph e a
- vertex :: a -> Graph e a
- edge :: e -> a -> a -> Graph e a
- (-<) :: a -> e -> (a, e)
- (>-) :: (a, e) -> a -> Graph e a
- overlay :: Monoid e => Graph e a -> Graph e a -> Graph e a
- connect :: e -> Graph e a -> Graph e a -> Graph e a
- vertices :: Monoid e => [a] -> Graph e a
- edges :: Monoid e => [(e, a, a)] -> Graph e a
- overlays :: Monoid e => [Graph e a] -> Graph e a
- foldg :: b -> (a -> b) -> (e -> b -> b -> b) -> Graph e a -> b
- buildg :: (forall r. r -> (a -> r) -> (e -> r -> r -> r) -> r) -> Graph e a
- isSubgraphOf :: (Eq e, Monoid e, Ord a) => Graph e a -> Graph e a -> Bool
- isEmpty :: Graph e a -> Bool
- size :: Graph e a -> Int
- hasVertex :: Eq a => a -> Graph e a -> Bool
- hasEdge :: (Eq e, Monoid e, Ord a) => a -> a -> Graph e a -> Bool
- edgeLabel :: (Eq a, Monoid e) => a -> a -> Graph e a -> e
- vertexList :: Ord a => Graph e a -> [a]
- edgeList :: (Eq e, Monoid e, Ord a) => Graph e a -> [(e, a, a)]
- vertexSet :: Ord a => Graph e a -> Set a
- edgeSet :: (Eq e, Monoid e, Ord a) => Graph e a -> Set (e, a, a)
- removeVertex :: Eq a => a -> Graph e a -> Graph e a
- removeEdge :: (Eq a, Eq e, Monoid e) => a -> a -> Graph e a -> Graph e a
- replaceVertex :: Eq a => a -> a -> Graph e a -> Graph e a
- replaceEdge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> Graph e a -> Graph e a
- transpose :: Graph e a -> Graph e a
- emap :: (e -> f) -> Graph e a -> Graph f a
- induce :: (a -> Bool) -> Graph e a -> Graph e a
- induceJust :: Graph e (Maybe a) -> Graph e a
- closure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a
- reflexiveClosure :: (Ord a, Semiring e) => Graph e a -> Graph e a
- symmetricClosure :: Monoid e => Graph e a -> Graph e a
- transitiveClosure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a
- type UnlabelledGraph a = Graph Any a
- type Automaton a s = Graph (RegularExpression a) s
- type Network e a = Graph (Distance e) a
- data Context e a = Context {}
- context :: (Eq e, Monoid e) => (a -> Bool) -> Graph e a -> Maybe (Context e a)
Algebraic data type for edge-labelled graphs
Edge-labelled graphs, where the type variable e stands for edge labels.
For example, Graph Bool a is isomorphic to unlabelled graphs defined in
the top-level module Algebra.Graph.Graph, where False and True denote
the lack of and the existence of an unlabelled edge, respectively.
Instances
Construct the empty graph. An alias for the constructor Empty.
isEmptyempty == TruehasVertexx empty == FalsevertexCountempty == 0edgeCountempty == 0
vertex :: a -> Graph e a Source #
Construct the graph comprising a single isolated vertex. An alias for the
constructor Vertex.
isEmpty(vertex x) == FalsehasVertexx (vertex y) == (x == y)vertexCount(vertex x) == 1edgeCount(vertex x) == 0
edge :: e -> a -> a -> Graph e a Source #
Construct the graph comprising a single labelled edge.
edge e x y ==connecte (vertexx) (vertexy) edgezerox y ==vertices[x,y]hasEdgex y (edge e x y) == (e /=zero)edgeLabelx y (edge e x y) == eedgeCount(edge e x y) == if e ==zerothen 0 else 1vertexCount(edge e 1 1) == 1vertexCount(edge e 1 2) == 2
(-<) :: a -> e -> (a, e) infixl 5 Source #
The left-hand part of a convenient ternary-ish operator x-<e>-y for
creating labelled edges.
x -<e>- y == edge e x y
(>-) :: (a, e) -> a -> Graph e a infixl 5 Source #
The right-hand part of a convenient ternary-ish operator x-<e>-y for
creating labelled edges.
x -<e>- y == edge e x y
overlay :: Monoid e => Graph e a -> Graph e a -> Graph e a Source #
Overlay two graphs. An alias for Connect zero.
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 +edgeCountyvertexCount(overlay 1 2) == 2edgeCount(overlay 1 2) == 0
Note: overlay composes edges in parallel using the operator <+> with
zero acting as the identity:
edgeLabelx y $ overlay (edgee x y) (edgezerox y) == eedgeLabelx y $ overlay (edgee x y) (edgef x y) == e<+>f
Furthermore, when applied to transitive graphs, overlay composes edges in
sequence using the operator <.> with one acting as the identity:
edgeLabelx z $transitiveClosure(overlay (edgee x y) (edgeoney z)) == eedgeLabelx z $transitiveClosure(overlay (edgee x y) (edgef y z)) == e<.>f
connect :: e -> Graph e a -> Graph e a -> Graph e a Source #
Connect two graphs with edges labelled by a given label. An alias for
Connect.
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 e x y) ==isEmptyx &&isEmptyyhasVertexz (connect e x y) ==hasVertexz x ||hasVertexz yvertexCount(connect e x y) >=vertexCountxvertexCount(connect e x y) <=vertexCountx +vertexCountyedgeCount(connect e x y) <=vertexCountx *vertexCounty +edgeCountx +edgeCountyvertexCount(connect e 1 2) == 2edgeCount(connect e 1 2) == if e ==zerothen 0 else 1
vertices :: Monoid e => [a] -> Graph e 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 :: Monoid e => [Graph e a] -> Graph e 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
Graph folding
foldg :: b -> (a -> b) -> (e -> b -> b -> b) -> Graph e 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 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.
foldgemptyvertexconnect==idfoldgemptyvertex(fmapflipconnect) ==transposefoldg 1 (const1) (const(+)) ==sizefoldg True (constFalse) (const(&&)) ==isEmptyfoldg False (== x) (const(||)) ==hasVertexx foldg Set.emptySet.singleton(constSet.union) ==vertexSet
buildg :: (forall r. r -> (a -> r) -> (e -> r -> r -> r) -> r) -> Graph e a Source #
Build a graph given an interpretation of the three graph construction
primitives empty, vertex and connect, in this order. See examples for
further clarification.
buildg f == femptyvertexconnectbuildg (\e _ _ -> e) ==emptybuildg (\_ v _ -> v x) ==vertexx buildg (\e v c -> c l (foldge v c x) (foldge v c y)) ==connectl x y buildg (\e v c ->foldr(czero) e (mapv xs)) ==verticesxs buildg (\e v c ->foldge v (flip. c) g) ==transposegfoldge v c (buildg f) == f e v c
Relations on graphs
isSubgraphOf :: (Eq e, Monoid e, Ord a) => Graph e a -> Graph e 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 x y ==> x <= y
Graph properties
isEmpty :: Graph e 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 $edgee x y) == False
hasVertex :: Eq a => a -> Graph e 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
edgeLabel :: (Eq a, Monoid e) => a -> a -> Graph e a -> e Source #
Extract the label of a specified edge from a graph.
vertexList :: Ord a => Graph e a -> [a] Source #
Graph transformation
removeEdge :: (Eq a, Eq e, Monoid e) => a -> a -> Graph e a -> Graph e a Source #
Remove an edge from a given graph. Complexity: O(s) time, memory and size.
removeEdge x y (edgee x 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 * 2
replaceVertex :: Eq a => a -> a -> Graph e a -> Graph e 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 ==fmap(\v -> if v == x then y else v)
emap :: (e -> f) -> Graph e a -> Graph f a Source #
Transform a graph by applying a function to each of its edge labels. Complexity: O(s) time, memory and size.
The function h is required to be a homomorphism on the underlying type of
labels e. At the very least it must preserve zero and <+>:
hzero==zeroh x<+>h y == h (x<+>y)
If e is also a semiring, then h must also preserve the multiplicative
structure:
hone==oneh x<.>h y == h (x<.>y)
If the above requirements hold, then the implementation provides the following guarantees.
emap hempty==emptyemap h (vertexx) ==vertexx emap h (edgee x y) ==edge(h e) x y emap h (overlayx y) ==overlay(emap h x) (emap h y) emap h (connecte x y) ==connect(h e) (emap h x) (emap h y) emapid==idemap g . emap h == emap (g . h)
induce :: (a -> Bool) -> Graph e a -> Graph e 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 e (Maybe a) -> Graph e 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
Relational operations
closure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a Source #
Compute the reflexive and transitive closure of a graph over the underlying star semiring using the Warshall-Floyd-Kleene algorithm.
closureempty==emptyclosure (vertexx) ==edgeonex x closure (edgee x x) ==edgeonex x closure (edgee x y) ==edges[(one,x,x), (e,x,y), (one,y,y)] closure ==reflexiveClosure.transitiveClosureclosure ==transitiveClosure.reflexiveClosureclosure . closure == closurepostSetx (closure y) == Set.fromList(reachabley x)
reflexiveClosure :: (Ord a, Semiring e) => Graph e a -> Graph e a Source #
Compute the reflexive closure of a graph over the underlying semiring by
adding a self-loop of weight one to every vertex.
Complexity: O(n * log(n)) time.
reflexiveClosureempty==emptyreflexiveClosure (vertexx) ==edgeonex x reflexiveClosure (edgee x x) ==edgeonex x reflexiveClosure (edgee x y) ==edges[(one,x,x), (e,x,y), (one,y,y)] reflexiveClosure . reflexiveClosure == reflexiveClosure
symmetricClosure :: Monoid e => Graph e a -> Graph e a Source #
Compute the symmetric closure of a graph by overlaying it with its own transpose. Complexity: O((n + m) * log(n)) time.
symmetricClosureempty==emptysymmetricClosure (vertexx) ==vertexx symmetricClosure (edgee x y) ==edges[(e,x,y), (e,y,x)] symmetricClosure x ==overlayx (transposex) symmetricClosure . symmetricClosure == symmetricClosure
transitiveClosure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a Source #
Compute the transitive closure of a graph over the underlying star semiring using a modified version of the Warshall-Floyd-Kleene algorithm, which omits the reflexivity step.
transitiveClosureempty==emptytransitiveClosure (vertexx) ==vertexx transitiveClosure (edgee x y) ==edgee x y transitiveClosure . transitiveClosure == transitiveClosure
Types of edge-labelled graphs
type UnlabelledGraph a = Graph Any a Source #
A type synonym for unlabelled graphs.
type Automaton a s = Graph (RegularExpression a) s Source #
A type synonym for automata or labelled transition systems.
type Network e a = Graph (Distance e) a Source #
A network is a graph whose edges are labelled with distances.
Context
The Context of a subgraph comprises its inputs and outputs, i.e. all
the vertices that are connected to the subgraph's vertices (along with the
corresponding edge labels). Note that inputs and outputs can belong to the
subgraph itself. In general, there are no guarantees on the order of vertices
in inputs and outputs; furthermore, there may be repetitions.
context :: (Eq e, Monoid e) => (a -> Bool) -> Graph e a -> Maybe (Context e a) Source #
Extract the Context of a subgraph specified by a given predicate. Returns
Nothing if the specified subgraph is empty.
context (constFalse) x == Nothing context (== 1) (edgee 1 2) == if e ==zerothen Just (Context[] []) else Just (Context[ ] [(e,2)]) context (== 2) (edgee 1 2) == if e ==zerothen Just (Context[] []) else Just (Context[(e,1)] [ ]) context (constTrue ) (edgee 1 2) == if e ==zerothen Just (Context[] []) else Just (Context[(e,1)] [(e,2)]) context (== 4) (3 * 1 * 4 * 1 * 5) == Just (Context[(one,3), (one,1)] [(one,1), (one,5)])