algebraic-graphs-0.2: A library for algebraic graph construction and transformation

Copyright(c) Andrey Mokhov 2016-2018
LicenseMIT (see the file LICENSE)
Maintainerandrey.mokhov@gmail.com
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

Algebra.Graph.AdjacencyIntMap

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 AdjacencyIntMap data type, as well as associated operations and 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 Source #

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))

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.

Instances
Eq AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap.Internal

Num AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap.Internal

Show AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap.Internal

NFData AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.AdjacencyIntMap.Internal

Methods

rnf :: AdjacencyIntMap -> () #

ToGraph AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.ToGraph

Associated Types

type ToVertex AdjacencyIntMap :: * Source #

Methods

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

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

isEmpty :: AdjacencyIntMap -> Bool Source #

size :: AdjacencyIntMap -> Int Source #

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

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

vertexCount :: AdjacencyIntMap -> Int Source #

edgeCount :: AdjacencyIntMap -> Int Source #

vertexList :: AdjacencyIntMap -> [ToVertex AdjacencyIntMap] Source #

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

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

vertexIntSet :: AdjacencyIntMap -> IntSet Source #

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

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

preIntSet :: Int -> AdjacencyIntMap -> IntSet Source #

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

postIntSet :: Int -> AdjacencyIntMap -> IntSet Source #

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

adjacencyMap :: AdjacencyIntMap -> Map (ToVertex AdjacencyIntMap) (Set (ToVertex AdjacencyIntMap)) Source #

adjacencyIntMap :: AdjacencyIntMap -> IntMap IntSet Source #

adjacencyMapTranspose :: AdjacencyIntMap -> Map (ToVertex AdjacencyIntMap) (Set (ToVertex AdjacencyIntMap)) Source #

adjacencyIntMapTranspose :: AdjacencyIntMap -> IntMap IntSet Source #

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

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

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

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

topSort :: AdjacencyIntMap -> Maybe [ToVertex AdjacencyIntMap] Source #

isAcyclic :: AdjacencyIntMap -> Bool Source #

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

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

toAdjacencyIntMap :: AdjacencyIntMap -> AdjacencyIntMap Source #

toAdjacencyIntMapTranspose :: AdjacencyIntMap -> AdjacencyIntMap Source #

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

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

Graph AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.Class

Associated Types

type Vertex AdjacencyIntMap :: * Source #

type ToVertex AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.ToGraph

type Vertex AdjacencyIntMap Source # 
Instance details

Defined in Algebra.Graph.Class

adjacencyIntMap :: AdjacencyIntMap -> IntMap IntSet Source #

The adjacency map of the 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)]

Basic graph construction primitives

empty :: AdjacencyIntMap Source #

Construct the empty graph. Complexity: O(1) time and memory.

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

vertex :: Int -> AdjacencyIntMap Source #

Construct the graph comprising a single isolated vertex. Complexity: O(1) time and memory.

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

edge :: Int -> Int -> AdjacencyIntMap Source #

Construct the graph comprising a single edge. Complexity: O(1) time, memory.

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 Source #

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 Source #

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 Source #

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
hasVertex x  . vertices == elem x
vertexCount  . vertices == length . nub
vertexIntSet . vertices == IntSet.fromList

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

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
edgeCount . edges == length . nub
edgeList . edges  == nub . sort

overlays :: [AdjacencyIntMap] -> AdjacencyIntMap Source #

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 Source #

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 Source #

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

Graph properties

isEmpty :: AdjacencyIntMap -> Bool Source #

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 Source #

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

hasVertex x empty            == False
hasVertex x (vertex x)       == True
hasVertex 1 (vertex 2)       == False
hasVertex x . removeVertex x == const False

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

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 Source #

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

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

edgeCount :: AdjacencyIntMap -> Int Source #

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] Source #

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)] Source #

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])] Source #

The sorted adjacency list of a graph. Complexity: O(n + m) time and O(m) 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 Source #

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) Source #

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 Source #

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 Source #

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 Source #

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 Source #

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 Source #

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 Source #

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 Source #

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 Source #

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)

tree :: Tree Int -> AdjacencyIntMap Source #

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 Source #

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 Source #

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 Source #

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 Source #

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 Source #

Merge vertices satisfying a given predicate into a given vertex. Complexity: O((n + m) * log(n)) time, 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

transpose :: AdjacencyIntMap -> AdjacencyIntMap Source #

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 Source #

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 Source #

Construct the induced subgraph of a given graph by removing the vertices that do not satisfy a given predicate. Complexity: O(m) time, assuming that the predicate takes O(1) to be evaluated.

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

Algorithms

dfsForest :: AdjacencyIntMap -> Forest Int Source #

Compute the depth-first search forest of a graph that corresponds to searching from each of the graph vertices in the Ord a order.

dfsForest empty                       == []
forest (dfsForest $ edge 1 1)         == vertex 1
forest (dfsForest $ edge 1 2)         == edge 1 2
forest (dfsForest $ edge 2 1)         == vertices [1,2]
isSubgraphOf (forest $ dfsForest x) x == True
isDfsForestOf (dfsForest x) x         == True
dfsForest . forest . dfsForest        == dfsForest
dfsForest (vertices vs)               == map (\v -> Node v []) (nub $ sort vs)
dfsForestFrom (vertexList x) x        == dfsForest x
dfsForest $ 3 * (1 + 4) * (1 + 5)     == [ Node { rootLabel = 1
                                                , subForest = [ Node { rootLabel = 5
                                                                     , subForest = [] }]}
                                         , Node { rootLabel = 3
                                                , subForest = [ Node { rootLabel = 4
                                                                     , subForest = [] }]}]

dfsForestFrom :: [Int] -> AdjacencyIntMap -> Forest Int Source #

Compute the depth-first search forest of a graph, searching from each of the given vertices in order. Note that the resulting forest does not necessarily span the whole graph, as some vertices may be unreachable.

dfsForestFrom vs empty                           == []
forest (dfsForestFrom [1]   $ edge 1 1)          == vertex 1
forest (dfsForestFrom [1]   $ edge 1 2)          == edge 1 2
forest (dfsForestFrom [2]   $ edge 1 2)          == vertex 2
forest (dfsForestFrom [3]   $ edge 1 2)          == empty
forest (dfsForestFrom [2,1] $ edge 1 2)          == vertices [1,2]
isSubgraphOf (forest $ dfsForestFrom vs x) x     == True
isDfsForestOf (dfsForestFrom (vertexList x) x) x == True
dfsForestFrom (vertexList x) x                   == dfsForest x
dfsForestFrom vs             (vertices vs)       == map (\v -> Node v []) (nub vs)
dfsForestFrom []             x                   == []
dfsForestFrom [1,4] $ 3 * (1 + 4) * (1 + 5)      == [ Node { rootLabel = 1
                                                           , subForest = [ Node { rootLabel = 5
                                                                                , subForest = [] }
                                                    , Node { rootLabel = 4
                                                           , subForest = [] }]

dfs :: [Int] -> AdjacencyIntMap -> [Int] Source #

Compute the list of vertices visited by the depth-first search in a graph, when searching from each of the given vertices in order.

dfs vs    $ empty                    == []
dfs [1]   $ edge 1 1                 == [1]
dfs [1]   $ edge 1 2                 == [1,2]
dfs [2]   $ edge 1 2                 == [2]
dfs [3]   $ edge 1 2                 == []
dfs [1,2] $ edge 1 2                 == [1,2]
dfs [2,1] $ edge 1 2                 == [2,1]
dfs []    $ x                        == []
dfs [1,4] $ 3 * (1 + 4) * (1 + 5)    == [1,5,4]
isSubgraphOf (vertices $ dfs vs x) x == True

reachable :: Int -> AdjacencyIntMap -> [Int] Source #

Compute the list of vertices that are reachable from a given source vertex in a graph. The vertices in the resulting list appear in the depth-first order.

reachable x $ empty                       == []
reachable 1 $ vertex 1                    == [1]
reachable 1 $ vertex 2                    == []
reachable 1 $ edge 1 1                    == [1]
reachable 1 $ edge 1 2                    == [1,2]
reachable 4 $ path    [1..8]              == [4..8]
reachable 4 $ circuit [1..8]              == [4..8] ++ [1..3]
reachable 8 $ clique  [8,7..1]            == [8] ++ [1..7]
isSubgraphOf (vertices $ reachable x y) y == True

topSort :: AdjacencyIntMap -> Maybe [Int] Source #

Compute the topological sort of a graph or return Nothing if the graph is cyclic.

topSort (1 * 2 + 3 * 1)               == Just [3,1,2]
topSort (1 * 2 + 2 * 1)               == Nothing
fmap (flip isTopSortOf x) (topSort x) /= Just False
isJust . topSort                      == isAcyclic

isAcyclic :: AdjacencyIntMap -> Bool Source #

Check if a given graph is acyclic.

isAcyclic (1 * 2 + 3 * 1) == True
isAcyclic (1 * 2 + 2 * 1) == False
isAcyclic . circuit       == null
isAcyclic                 == isJust . topSort

Correctness properties

isDfsForestOf :: Forest Int -> AdjacencyIntMap -> Bool Source #

Check if a given forest is a correct depth-first search forest of a graph. The implementation is based on the paper "Depth-First Search and Strong Connectivity in Coq" by François Pottier.

isDfsForestOf []                              empty            == True
isDfsForestOf []                              (vertex 1)       == False
isDfsForestOf [Node 1 []]                     (vertex 1)       == True
isDfsForestOf [Node 1 []]                     (vertex 2)       == False
isDfsForestOf [Node 1 [], Node 1 []]          (vertex 1)       == False
isDfsForestOf [Node 1 []]                     (edge 1 1)       == True
isDfsForestOf [Node 1 []]                     (edge 1 2)       == False
isDfsForestOf [Node 1 [], Node 2 []]          (edge 1 2)       == False
isDfsForestOf [Node 2 [], Node 1 []]          (edge 1 2)       == True
isDfsForestOf [Node 1 [Node 2 []]]            (edge 1 2)       == True
isDfsForestOf [Node 1 [], Node 2 []]          (vertices [1,2]) == True
isDfsForestOf [Node 2 [], Node 1 []]          (vertices [1,2]) == True
isDfsForestOf [Node 1 [Node 2 []]]            (vertices [1,2]) == False
isDfsForestOf [Node 1 [Node 2 [Node 3 []]]]   (path [1,2,3])   == True
isDfsForestOf [Node 1 [Node 3 [Node 2 []]]]   (path [1,2,3])   == False
isDfsForestOf [Node 3 [], Node 1 [Node 2 []]] (path [1,2,3])   == True
isDfsForestOf [Node 2 [Node 3 []], Node 1 []] (path [1,2,3])   == True
isDfsForestOf [Node 1 [], Node 2 [Node 3 []]] (path [1,2,3])   == False

isTopSortOf :: [Int] -> AdjacencyIntMap -> Bool Source #

Check if a given list of vertices is a correct topological sort of a graph.

isTopSortOf [3,1,2] (1 * 2 + 3 * 1) == True
isTopSortOf [1,2,3] (1 * 2 + 3 * 1) == False
isTopSortOf []      (1 * 2 + 3 * 1) == False
isTopSortOf []      empty           == True
isTopSortOf [x]     (vertex x)      == True
isTopSortOf [x]     (edge x x)      == False