algebraic-graphs-0.7: A library for algebraic graph construction and transformation
Copyright(c) Andrey Mokhov 2016-2022
LicenseMIT (see the file LICENSE)
Maintainerandrey.mokhov@gmail.com
Stabilityexperimental
Safe HaskellSafe-Inferred
LanguageHaskell2010

Algebra.Graph.AdjacencyIntMap

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 AdjacencyIntMap data type and associated functions. See Algebra.Graph.AdjacencyIntMap.Algorithm for implementations of basic graph algorithms. AdjacencyIntMap is an instance of the Graph type class, which can be used for polymorphic graph construction and manipulation. See Algebra.Graph.AdjacencyMap for graphs with non-Int vertices.

Synopsis

Data structure

data AdjacencyIntMap #

The AdjacencyIntMap data type represents a graph by a map of vertices to their adjacency sets. 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))

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 Show instance is defined using basic graph construction primitives:

show (empty     :: AdjacencyIntMap Int) == "empty"
show (1         :: AdjacencyIntMap Int) == "vertex 1"
show (1 + 2     :: AdjacencyIntMap Int) == "vertices [1,2]"
show (1 * 2     :: AdjacencyIntMap Int) == "edge 1 2"
show (1 * 2 * 3 :: AdjacencyIntMap Int) == "edges [(1,2),(1,3),(2,3)]"
show (1 * 2 + 3 :: AdjacencyIntMap Int) == "overlay (vertex 3) (edge 1 2)"

The Eq instance satisfies all axioms of algebraic graphs:

  • overlay is commutative and associative:

          x + y == y + x
    x + (y + z) == (x + y) + z
  • connect is associative and has empty as the identity:

      x * empty == x
      empty * x == x
    x * (y * z) == (x * y) * z
  • connect distributes over overlay:

    x * (y + z) == x * y + x * z
    (x + y) * z == x * z + y * z
  • connect can be decomposed:

    x * y * z == x * y + x * z + y * z

The following useful theorems can be proved from the above set of axioms.

  • overlay has empty as the identity and is idempotent:

      x + empty == x
      empty + x == x
          x + x == x
  • Absorption 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 and m will denote the number of vertices and edges in the graph, respectively.

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:

vertex 1 < vertex 2
vertex 3 < edge 1 2
vertex 1 < edge 1 1
edge 1 1 < edge 1 2
edge 1 2 < edge 1 1 + edge 2 2
edge 1 2 < edge 1 3

Note that the resulting order refines the isSubgraphOf relation and is compatible with overlay and connect operations:

isSubgraphOf x y ==> x <= y
empty <= x
x     <= x + y
x + y <= x * y

Instances

Instances details
Graph AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.Class

Associated Types

type Vertex AdjacencyIntMap #

ToGraph AdjacencyIntMap #

See Algebra.Graph.AdjacencyIntMap.

Instance details

Defined in Algebra.Graph.ToGraph

Associated Types

type ToVertex AdjacencyIntMap #

Methods

toGraph :: AdjacencyIntMap -> Graph (ToVertex AdjacencyIntMap) #

foldg :: r -> (ToVertex AdjacencyIntMap -> r) -> (r -> r -> r) -> (r -> r -> r) -> AdjacencyIntMap -> r #

isEmpty :: AdjacencyIntMap -> Bool #

hasVertex :: ToVertex AdjacencyIntMap -> AdjacencyIntMap -> Bool #

hasEdge :: ToVertex AdjacencyIntMap -> ToVertex AdjacencyIntMap -> AdjacencyIntMap -> Bool #

vertexCount :: AdjacencyIntMap -> Int #

edgeCount :: AdjacencyIntMap -> Int #

vertexList :: AdjacencyIntMap -> [ToVertex AdjacencyIntMap] #

edgeList :: AdjacencyIntMap -> [(ToVertex AdjacencyIntMap, ToVertex AdjacencyIntMap)] #

vertexSet :: AdjacencyIntMap -> Set (ToVertex AdjacencyIntMap) #

vertexIntSet :: AdjacencyIntMap -> IntSet #

edgeSet :: AdjacencyIntMap -> Set (ToVertex AdjacencyIntMap, ToVertex AdjacencyIntMap) #

preSet :: ToVertex AdjacencyIntMap -> AdjacencyIntMap -> Set (ToVertex AdjacencyIntMap) #

preIntSet :: Int -> AdjacencyIntMap -> IntSet #

postSet :: ToVertex AdjacencyIntMap -> AdjacencyIntMap -> Set (ToVertex AdjacencyIntMap) #

postIntSet :: Int -> AdjacencyIntMap -> IntSet #

adjacencyList :: AdjacencyIntMap -> [(ToVertex AdjacencyIntMap, [ToVertex AdjacencyIntMap])] #

dfsForest :: AdjacencyIntMap -> Forest (ToVertex AdjacencyIntMap) #

dfsForestFrom :: AdjacencyIntMap -> [ToVertex AdjacencyIntMap] -> Forest (ToVertex AdjacencyIntMap) #

dfs :: AdjacencyIntMap -> [ToVertex AdjacencyIntMap] -> [ToVertex AdjacencyIntMap] #

reachable :: AdjacencyIntMap -> ToVertex AdjacencyIntMap -> [ToVertex AdjacencyIntMap] #

topSort :: AdjacencyIntMap -> Either (Cycle (ToVertex AdjacencyIntMap)) [ToVertex AdjacencyIntMap] #

isAcyclic :: AdjacencyIntMap -> Bool #

toAdjacencyMap :: AdjacencyIntMap -> AdjacencyMap (ToVertex AdjacencyIntMap) #

toAdjacencyMapTranspose :: AdjacencyIntMap -> AdjacencyMap (ToVertex AdjacencyIntMap) #

toAdjacencyIntMap :: AdjacencyIntMap -> AdjacencyIntMap #

toAdjacencyIntMapTranspose :: AdjacencyIntMap -> AdjacencyIntMap #

isDfsForestOf :: Forest (ToVertex AdjacencyIntMap) -> AdjacencyIntMap -> Bool #

isTopSortOf :: [ToVertex AdjacencyIntMap] -> AdjacencyIntMap -> Bool #

Monoid AdjacencyIntMap #

Defined via overlay and empty.

Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Semigroup AdjacencyIntMap #

Defined via overlay.

Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Generic AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Associated Types

type Rep AdjacencyIntMap :: Type -> Type

Num AdjacencyIntMap #

Note: this does not satisfy the usual ring laws; see AdjacencyIntMap for more details.

Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Show AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Methods

showsPrec :: Int -> AdjacencyIntMap -> ShowS

show :: AdjacencyIntMap -> String

showList :: [AdjacencyIntMap] -> ShowS

NFData AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Methods

rnf :: AdjacencyIntMap -> ()

Eq AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

Ord AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

type Vertex AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.Class

type ToVertex AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.ToGraph

type Rep AdjacencyIntMap # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap

type Rep AdjacencyIntMap = D1 ('MetaData "AdjacencyIntMap" "Algebra.Graph.AdjacencyIntMap" "algebraic-graphs-0.7-B119zIVMD2d6laIP0nf6Fh" 'True) (C1 ('MetaCons "AM" 'PrefixI 'True) (S1 ('MetaSel ('Just "adjacencyIntMap") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (IntMap IntSet))))

adjacencyIntMap :: AdjacencyIntMap -> IntMap IntSet #

The adjacency map of a graph: each vertex is associated with a set of its direct successors. Complexity: O(1) time and memory.

adjacencyIntMap empty      == IntMap.empty
adjacencyIntMap (vertex x) == IntMap.singleton x IntSet.empty
adjacencyIntMap (edge 1 1) == IntMap.singleton 1 (IntSet.singleton 1)
adjacencyIntMap (edge 1 2) == IntMap.fromList [(1,IntSet.singleton 2), (2,IntSet.empty)]

fromAdjacencyMap :: AdjacencyMap Int -> AdjacencyIntMap #

Construct an AdjacencyIntMap from an AdjacencyMap with vertices of type Int. Complexity: O(n + m) time and memory.

fromAdjacencyMap == stars . AdjacencyMap.adjacencyList

Basic graph construction primitives

empty :: AdjacencyIntMap #

Construct the empty graph.

isEmpty     empty == True
hasVertex x empty == False
vertexCount empty == 0
edgeCount   empty == 0

vertex :: Int -> AdjacencyIntMap #

Construct the graph comprising a single isolated vertex.

isEmpty     (vertex x) == False
hasVertex x (vertex y) == (x == y)
vertexCount (vertex x) == 1
edgeCount   (vertex x) == 0

edge :: Int -> Int -> AdjacencyIntMap #

Construct the graph comprising a single edge.

edge x y               == connect (vertex x) (vertex y)
hasEdge x y (edge x y) == True
edgeCount   (edge x y) == 1
vertexCount (edge 1 1) == 1
vertexCount (edge 1 2) == 2

overlay :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap #

Overlay two graphs. This is a commutative, associative and idempotent operation with the identity empty. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

isEmpty     (overlay x y) == isEmpty   x   && isEmpty   y
hasVertex z (overlay x y) == hasVertex z x || hasVertex z y
vertexCount (overlay x y) >= vertexCount x
vertexCount (overlay x y) <= vertexCount x + vertexCount y
edgeCount   (overlay x y) >= edgeCount x
edgeCount   (overlay x y) <= edgeCount x   + edgeCount y
vertexCount (overlay 1 2) == 2
edgeCount   (overlay 1 2) == 0

connect :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap #

Connect two graphs. This is an associative operation with the identity empty, which distributes over overlay and obeys the decomposition axiom. Complexity: O((n + m) * log(n)) time and O(n + m) memory. 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) == isEmpty   x   && isEmpty   y
hasVertex z (connect x y) == hasVertex z x || hasVertex z y
vertexCount (connect x y) >= vertexCount x
vertexCount (connect x y) <= vertexCount x + vertexCount y
edgeCount   (connect x y) >= edgeCount x
edgeCount   (connect x y) >= edgeCount y
edgeCount   (connect x y) >= vertexCount x * vertexCount y
edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y
vertexCount (connect 1 2) == 2
edgeCount   (connect 1 2) == 1

vertices :: [Int] -> AdjacencyIntMap #

Construct the graph comprising a given list of isolated vertices. Complexity: O(L * log(L)) time and O(L) memory, where L is the length of the given list.

vertices []             == empty
vertices [x]            == vertex x
vertices                == overlays . map vertex
hasVertex x  . vertices == elem x
vertexCount  . vertices == length . nub
vertexIntSet . vertices == IntSet.fromList

edges :: [(Int, Int)] -> AdjacencyIntMap #

Construct the graph from a list of edges. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

edges []          == empty
edges [(x,y)]     == edge x y
edges             == overlays . map (uncurry edge)
edgeCount . edges == length . nub
edgeList . edges  == nub . sort

overlays :: [AdjacencyIntMap] -> AdjacencyIntMap #

Overlay a given list of graphs. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

overlays []        == empty
overlays [x]       == x
overlays [x,y]     == overlay x y
overlays           == foldr overlay empty
isEmpty . overlays == all isEmpty

connects :: [AdjacencyIntMap] -> AdjacencyIntMap #

Connect a given list of graphs. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

connects []        == empty
connects [x]       == x
connects [x,y]     == connect x y
connects           == foldr connect empty
isEmpty . connects == all isEmpty

Relations on graphs

isSubgraphOf :: AdjacencyIntMap -> AdjacencyIntMap -> Bool #

The isSubgraphOf function takes two graphs and returns True if the first graph is a subgraph of the second. Complexity: O((n + m) * log(n)) time.

isSubgraphOf empty         x             ==  True
isSubgraphOf (vertex x)    empty         ==  False
isSubgraphOf x             (overlay x y) ==  True
isSubgraphOf (overlay x y) (connect x y) ==  True
isSubgraphOf (path xs)     (circuit xs)  ==  True
isSubgraphOf x y                         ==> x <= y

Graph properties

isEmpty :: AdjacencyIntMap -> Bool #

Check if a graph is empty. Complexity: O(1) time.

isEmpty empty                       == True
isEmpty (overlay empty empty)       == True
isEmpty (vertex x)                  == False
isEmpty (removeVertex x $ vertex x) == True
isEmpty (removeEdge x y $ edge x y) == False

hasVertex :: Int -> AdjacencyIntMap -> Bool #

Check if a graph contains a given vertex. Complexity: O(log(n)) time.

hasVertex x empty            == False
hasVertex x (vertex y)       == (x == y)
hasVertex x . removeVertex x == const False

hasEdge :: Int -> Int -> AdjacencyIntMap -> Bool #

Check if a graph contains a given edge. Complexity: O(log(n)) time.

hasEdge x y empty            == False
hasEdge x y (vertex z)       == False
hasEdge x y (edge x y)       == True
hasEdge x y . removeEdge x y == const False
hasEdge x y                  == elem (x,y) . edgeList

vertexCount :: AdjacencyIntMap -> Int #

The number of vertices in a graph. Complexity: O(1) time.

vertexCount empty             ==  0
vertexCount (vertex x)        ==  1
vertexCount                   ==  length . vertexList
vertexCount x < vertexCount y ==> x < y

edgeCount :: AdjacencyIntMap -> Int #

The number of edges in a graph. Complexity: O(n) time.

edgeCount empty      == 0
edgeCount (vertex x) == 0
edgeCount (edge x y) == 1
edgeCount            == length . edgeList

vertexList :: AdjacencyIntMap -> [Int] #

The sorted list of vertices of a given graph. Complexity: O(n) time and memory.

vertexList empty      == []
vertexList (vertex x) == [x]
vertexList . vertices == nub . sort

edgeList :: AdjacencyIntMap -> [(Int, Int)] #

The sorted list of edges of a graph. Complexity: O(n + m) time and O(m) memory.

edgeList empty          == []
edgeList (vertex x)     == []
edgeList (edge x y)     == [(x,y)]
edgeList (star 2 [3,1]) == [(2,1), (2,3)]
edgeList . edges        == nub . sort
edgeList . transpose    == sort . map swap . edgeList

adjacencyList :: AdjacencyIntMap -> [(Int, [Int])] #

The sorted adjacency list of a graph. Complexity: O(n + m) time and memory.

adjacencyList empty          == []
adjacencyList (vertex x)     == [(x, [])]
adjacencyList (edge 1 2)     == [(1, [2]), (2, [])]
adjacencyList (star 2 [3,1]) == [(1, []), (2, [1,3]), (3, [])]
stars . adjacencyList        == id

vertexIntSet :: AdjacencyIntMap -> IntSet #

The set of vertices of a given graph. Complexity: O(n) time and memory.

vertexIntSet empty      == IntSet.empty
vertexIntSet . vertex   == IntSet.singleton
vertexIntSet . vertices == IntSet.fromList
vertexIntSet . clique   == IntSet.fromList

edgeSet :: AdjacencyIntMap -> Set (Int, Int) #

The set of edges of a given graph. Complexity: O((n + m) * log(m)) time and O(m) memory.

edgeSet empty      == Set.empty
edgeSet (vertex x) == Set.empty
edgeSet (edge x y) == Set.singleton (x,y)
edgeSet . edges    == Set.fromList

preIntSet :: Int -> AdjacencyIntMap -> IntSet #

The preset (here preIntSet) of an element x is the set of its direct predecessors. Complexity: O(n * log(n)) time and O(n) memory.

preIntSet x empty      == Set.empty
preIntSet x (vertex x) == Set.empty
preIntSet 1 (edge 1 2) == Set.empty
preIntSet y (edge x y) == Set.fromList [x]

postIntSet :: Int -> AdjacencyIntMap -> IntSet #

The postset (here postIntSet) of a vertex is the set of its direct successors.

postIntSet x empty      == IntSet.empty
postIntSet x (vertex x) == IntSet.empty
postIntSet x (edge x y) == IntSet.fromList [y]
postIntSet 2 (edge 1 2) == IntSet.empty

Standard families of graphs

path :: [Int] -> AdjacencyIntMap #

The path on a list of vertices. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

path []        == empty
path [x]       == vertex x
path [x,y]     == edge x y
path . reverse == transpose . path

circuit :: [Int] -> AdjacencyIntMap #

The circuit on a list of vertices. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

circuit []        == empty
circuit [x]       == edge x x
circuit [x,y]     == edges [(x,y), (y,x)]
circuit . reverse == transpose . circuit

clique :: [Int] -> AdjacencyIntMap #

The clique on a list of vertices. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

clique []         == empty
clique [x]        == vertex x
clique [x,y]      == edge x y
clique [x,y,z]    == edges [(x,y), (x,z), (y,z)]
clique (xs ++ ys) == connect (clique xs) (clique ys)
clique . reverse  == transpose . clique

biclique :: [Int] -> [Int] -> AdjacencyIntMap #

The biclique on two lists of vertices. Complexity: O(n * log(n) + m) time and O(n + m) memory.

biclique []      []      == empty
biclique [x]     []      == vertex x
biclique []      [y]     == vertex y
biclique [x1,x2] [y1,y2] == edges [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]
biclique xs      ys      == connect (vertices xs) (vertices ys)

star :: Int -> [Int] -> AdjacencyIntMap #

The star formed by a centre vertex connected to a list of leaves. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

star x []    == vertex x
star x [y]   == edge x y
star x [y,z] == edges [(x,y), (x,z)]
star x ys    == connect (vertex x) (vertices ys)

stars :: [(Int, [Int])] -> AdjacencyIntMap #

The stars formed by overlaying a list of stars. An inverse of adjacencyList. Complexity: O(L * log(n)) time, memory and size, where L is the total size of the input.

stars []                      == empty
stars [(x, [])]               == vertex x
stars [(x, [y])]              == edge x y
stars [(x, ys)]               == star x ys
stars                         == overlays . map (uncurry star)
stars . adjacencyList         == id
overlay (stars xs) (stars ys) == stars (xs ++ ys)

fromAdjacencyIntSets :: [(Int, IntSet)] -> AdjacencyIntMap #

Construct a graph from a list of adjacency sets; a variation of stars. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

fromAdjacencyIntSets []                                     == empty
fromAdjacencyIntSets [(x, IntSet.empty)]                    == vertex x
fromAdjacencyIntSets [(x, IntSet.singleton y)]              == edge x y
fromAdjacencyIntSets . map (fmap IntSet.fromList)           == stars
overlay (fromAdjacencyIntSets xs) (fromAdjacencyIntSets ys) == fromAdjacencyIntSets (xs ++ ys)

tree :: Tree Int -> AdjacencyIntMap #

The tree graph constructed from a given Tree data structure. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

tree (Node x [])                                         == vertex x
tree (Node x [Node y [Node z []]])                       == path [x,y,z]
tree (Node x [Node y [], Node z []])                     == star x [y,z]
tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges [(1,2), (1,3), (3,4), (3,5)]

forest :: Forest Int -> AdjacencyIntMap #

The forest graph constructed from a given Forest data structure. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

forest []                                                  == empty
forest [x]                                                 == tree x
forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == edges [(1,2), (1,3), (4,5)]
forest                                                     == overlays . map tree

Graph transformation

removeVertex :: Int -> AdjacencyIntMap -> AdjacencyIntMap #

Remove a vertex from a given graph. Complexity: O(n*log(n)) time.

removeVertex x (vertex x)       == empty
removeVertex 1 (vertex 2)       == vertex 2
removeVertex x (edge x x)       == empty
removeVertex 1 (edge 1 2)       == vertex 2
removeVertex x . removeVertex x == removeVertex x

removeEdge :: Int -> Int -> AdjacencyIntMap -> AdjacencyIntMap #

Remove an edge from a given graph. Complexity: O(log(n)) time.

removeEdge x y (edge x y)       == vertices [x,y]
removeEdge x y . removeEdge x y == removeEdge x y
removeEdge x y . removeVertex x == removeVertex x
removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2
removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2

replaceVertex :: Int -> Int -> AdjacencyIntMap -> AdjacencyIntMap #

The function replaceVertex x y replaces vertex x with vertex y in a given AdjacencyIntMap. If y already exists, x and y will be merged. Complexity: O((n + m) * log(n)) time.

replaceVertex x x            == id
replaceVertex x y (vertex x) == vertex y
replaceVertex x y            == mergeVertices (== x) y

mergeVertices :: (Int -> Bool) -> Int -> AdjacencyIntMap -> AdjacencyIntMap #

Merge vertices satisfying a given predicate into a given vertex. Complexity: O((n + m) * log(n)) time, assuming that the predicate takes constant time.

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

transpose :: AdjacencyIntMap -> AdjacencyIntMap #

Transpose a given graph. Complexity: O(m * log(n)) time, O(n + m) memory.

transpose empty       == empty
transpose (vertex x)  == vertex x
transpose (edge x y)  == edge y x
transpose . transpose == id
edgeList . transpose  == sort . map swap . edgeList

gmap :: (Int -> Int) -> AdjacencyIntMap -> AdjacencyIntMap #

Transform a graph by applying a function to each of its vertices. This is similar to Functor's fmap but can be used with non-fully-parametric AdjacencyIntMap. Complexity: O((n + m) * log(n)) time.

gmap f empty      == empty
gmap f (vertex x) == vertex (f x)
gmap f (edge x y) == edge (f x) (f y)
gmap id           == id
gmap f . gmap g   == gmap (f . g)

induce :: (Int -> Bool) -> AdjacencyIntMap -> AdjacencyIntMap #

Construct the induced subgraph of a given graph by removing the vertices that do not satisfy a given predicate. Complexity: O(n + m) time, assuming that the predicate takes constant time.

induce (const True ) x      == x
induce (const False) x      == empty
induce (/= x)               == removeVertex x
induce p . induce q         == induce (\x -> p x && q x)
isSubgraphOf (induce p x) x == True

Relational operations

compose :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap #

Left-to-right relational composition of graphs: vertices x and z are connected in the resulting graph if there is a vertex y, such that x is connected to y in the first graph, and y is connected to z in the second graph. There are no isolated vertices in the result. This operation is associative, has empty and single-vertex graphs as annihilating zeroes, and distributes over overlay. Complexity: O(n * m * log(n)) time and O(n + m) memory.

compose empty            x                == empty
compose x                empty            == empty
compose (vertex x)       y                == empty
compose x                (vertex y)       == empty
compose x                (compose y z)    == compose (compose x y) z
compose x                (overlay y z)    == overlay (compose x y) (compose x z)
compose (overlay x y)    z                == overlay (compose x z) (compose y z)
compose (edge x y)       (edge y z)       == edge x z
compose (path    [1..5]) (path    [1..5]) == edges [(1,3), (2,4), (3,5)]
compose (circuit [1..5]) (circuit [1..5]) == circuit [1,3,5,2,4]

closure :: AdjacencyIntMap -> AdjacencyIntMap #

Compute the reflexive and transitive closure of a graph. Complexity: O(n * m * log(n)^2) time.

closure empty            == empty
closure (vertex x)       == edge x x
closure (edge x x)       == edge x x
closure (edge x y)       == edges [(x,x), (x,y), (y,y)]
closure (path $ nub xs) == reflexiveClosure (clique $ nub xs)
closure                  == reflexiveClosure . transitiveClosure
closure                  == transitiveClosure . reflexiveClosure
closure . closure        == closure
postIntSet x (closure y) == IntSet.fromList (reachable y x)

reflexiveClosure :: AdjacencyIntMap -> AdjacencyIntMap #

Compute the reflexive closure of a graph by adding a self-loop to every vertex. Complexity: O(n * log(n)) time.

reflexiveClosure empty              == empty
reflexiveClosure (vertex x)         == edge x x
reflexiveClosure (edge x x)         == edge x x
reflexiveClosure (edge x y)         == edges [(x,x), (x,y), (y,y)]
reflexiveClosure . reflexiveClosure == reflexiveClosure

symmetricClosure :: AdjacencyIntMap -> AdjacencyIntMap #

Compute the symmetric closure of a graph by overlaying it with its own transpose. Complexity: O((n + m) * log(n)) time.

symmetricClosure empty              == empty
symmetricClosure (vertex x)         == vertex x
symmetricClosure (edge x y)         == edges [(x,y), (y,x)]
symmetricClosure x                  == overlay x (transpose x)
symmetricClosure . symmetricClosure == symmetricClosure

transitiveClosure :: AdjacencyIntMap -> AdjacencyIntMap #

Compute the transitive closure of a graph. Complexity: O(n * m * log(n)^2) time.

transitiveClosure empty               == empty
transitiveClosure (vertex x)          == vertex x
transitiveClosure (edge x y)          == edge x y
transitiveClosure (path $ nub xs)     == clique (nub xs)
transitiveClosure . transitiveClosure == transitiveClosure

Miscellaneous

consistent :: AdjacencyIntMap -> Bool #

Check that the internal graph representation is consistent, i.e. that all edges refer to existing vertices. It should be impossible to create an inconsistent adjacency map, and we use this function in testing.

consistent empty         == True
consistent (vertex x)    == True
consistent (overlay x y) == True
consistent (connect x y) == True
consistent (edge x y)    == True
consistent (edges xs)    == True
consistent (stars xs)    == True