HORIZON HASKELLDocslts/ghc-9.14.xd82dee82026-10-12Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · d82dee8 · 2026-10-12

Modulealgebraic-graphs-0.8Haskell2010

Algebra.Graph.Acyclic.AdjacencyMap

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 AdjacencyMap data type and for acyclic graphs, as well as associated operations and algorithms. To avoid name clashes with Algebra.Graph.AdjacencyMap, this module can be imported qualified:

import qualified Algebra.Graph.Acyclic.AdjacencyMap as Acyclic
  • 1 type
  • 32 values

Data structure

2 declarations
newtypenewtype AdjacencyMap a
#

The AdjacencyMap data type represents an acyclic graph by a map of vertices to their adjacency sets. Although the internal representation allows for cycles, the methods provided by this module cannot be used to construct a graph with cycles.

The Show instance is defined using basic graph construction primitives where possible, falling back to toAcyclic and Algebra.Graph.AdjacencyMap otherwise:

show empty                == "empty"
show (shrink 1)           == "vertex 1"
show (shrink $ 1 + 2)     == "vertices [1,2]"
show (shrink $ 1 * 2)     == "(fromJust . toAcyclic) (edge 1 2)"
show (shrink $ 1 * 2 * 3) == "(fromJust . toAcyclic) (edges [(1,2),(1,3),(2,3)])"
show (shrink $ 1 * 2 + 3) == "(fromJust . toAcyclic) (overlay (vertex 3) (edge 1 2))"

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.

Note that the resulting order refines the isSubgraphOf relation:

isSubgraphOf x y ==> x <= y
Instances3Eq, Ord, Show
  • Eq a => Eq (AdjacencyMap a)Defined in algebraic-graphs-0.8 · Algebra.Graph.Acyclic.AdjacencyMap
  • Ord a => Ord (AdjacencyMap a)Defined in algebraic-graphs-0.8 · Algebra.Graph.Acyclic.AdjacencyMap
  • (Ord a, Show a) => Show (AdjacencyMap a)Defined in algebraic-graphs-0.8 · Algebra.Graph.Acyclic.AdjacencyMap

Basic graph construction primitives

5 declarations

Relations on graphs

1 declaration

Graph properties

12 declarations
valueedgeList :: AdjacencyMap a -> [(a, a)]
#

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

edgeList empty            == []
edgeList (vertex x)       == []
edgeList (shrink $ 2 * 1) == [(2,1)]
edgeList . transpose      == sort . map swap . edgeList
valueadjacencyList :: AdjacencyMap a -> [(a, [a])]
#

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

adjacencyList empty            == []
adjacencyList (vertex x)       == [(x, [])]
adjacencyList (shrink $ 1 * 2) == [(1, [2]), (2, [])]
valuepreSet :: Ord a => a -> AdjacencyMap a -> Set a
#

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

preSet x empty            == Set.empty
preSet x (vertex x)       == Set.empty
preSet 1 (shrink $ 1 * 2) == Set.empty
preSet 2 (shrink $ 1 * 2) == Set.fromList [1]
Set.member x . preSet x   == const False

Graph transformation

5 declarations
valueremoveEdge :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a
#

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

removeEdge 1 2 (shrink $ 1 * 2)     == vertices [1,2]
removeEdge x y . removeEdge x y     == removeEdge x y
removeEdge x y . removeVertex x     == removeVertex x
removeEdge 1 2 (shrink $ 1 * 2 * 3) == shrink ((1 + 2) * 3)
valueinduce :: (a -> Bool) -> AdjacencyMap a -> AdjacencyMap a
#

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

Graph composition

1 declaration
valuebox
  1. :: (Ord a, Ord b)
  2. => AdjacencyMap a
  3. -> AdjacencyMap b
  4. -> AdjacencyMap (a, b)
#

Compute the Cartesian product of graphs. Complexity: O((n + m) * log(n)) time and O(n + m) memory.

edgeList (box (shrink $ 1 * 2) (shrink $ 10 * 20)) == [ ((1,10), (1,20))
                                                      , ((1,10), (2,10))
                                                      , ((1,20), (2,20))
                                                      , ((2,10), (2,20)) ]

Up to isomorphism between the resulting vertex types, this operation is commutative and associative, has singleton graphs as identities and empty as the annihilating zero. Below ~~ stands for 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 (vertex ())     ~~ x
box x empty           ~~ empty
transpose   (box x y) == box (transpose x) (transpose y)
vertexCount (box x y) == vertexCount x * vertexCount y
edgeCount   (box x y) <= vertexCount x * edgeCount y + edgeCount x * vertexCount y

Relational operations

1 declaration

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

transitiveClosure empty                    == empty
transitiveClosure (vertex x)               == vertex x
transitiveClosure (shrink $ 1 * 2 + 2 * 3) == shrink (1 * 2 + 1 * 3 + 2 * 3)
transitiveClosure . transitiveClosure      == transitiveClosure

Algorithms

2 declarations
valuescc :: Ord a => AdjacencyMap a -> AdjacencyMap (AdjacencyMap a)
#

Compute the acyclic condensation of a graph, where each vertex corresponds to a strongly-connected component of the original graph. Note that component graphs are non-empty, and are therefore of type Algebra.Graph.NonEmpty.AdjacencyMap.

           scc empty               == empty
           scc (vertex x)          == vertex (NonEmpty.vertex x)
           scc (edge 1 1)          == vertex (NonEmpty.edge 1 1)
edgeList $ scc (edge 1 2)          == [ (NonEmpty.vertex 1       , NonEmpty.vertex 2       ) ]
edgeList $ scc (3 * 1 * 4 * 1 * 5) == [ (NonEmpty.vertex 3       , NonEmpty.vertex 5       )
                                      , (NonEmpty.vertex 3       , NonEmpty.NonEmpty.clique1 [1,4,1])
                                      , (NonEmpty.NonEmpty.clique1 [1,4,1], NonEmpty.vertex 5       ) ]

Conversion to acyclic graphs

3 declarations
valuetoAcyclicOrd :: Ord a => AdjacencyMap a -> AdjacencyMap a
#

Construct an acyclic graph from a given adjacency map, keeping only edges (x,y) where x < y according to the supplied Ord a instance.

toAcyclicOrd empty       == empty
toAcyclicOrd . vertex    == vertex
toAcyclicOrd (1 + 2)     == shrink (1 + 2)
toAcyclicOrd (1 * 2)     == shrink (1 * 2)
toAcyclicOrd (2 * 1)     == shrink (1 + 2)
toAcyclicOrd (1 * 2 * 1) == shrink (1 * 2)
toAcyclicOrd (1 * 2 * 3) == shrink (1 * 2 * 3)
valueshrink :: Ord a => AdjacencyMap a -> AdjacencyMap a
#

Construct an acyclic graph from a given adjacency map using scc. If the graph is acyclic, it is returned as is. If the graph is cyclic, then a representative for every strongly connected component in its condensation graph is chosen and these representatives are used to build an acyclic graph.

shrink . vertex      == vertex
shrink . vertices    == vertices
shrink . fromAcyclic == id

Miscellaneous

1 declaration
valueconsistent :: Ord a => AdjacencyMap a -> Bool
#

Check if the internal representation of an acyclic graph is consistent, i.e. that all edges refer to existing vertices and the graph is acyclic. It should be impossible to create an inconsistent AdjacencyMap.

consistent empty                 == True
consistent (vertex x)            == True
consistent (vertices xs)         == True
consistent (union x y)           == True
consistent (join x y)            == True
consistent (transpose x)         == True
consistent (box x y)             == True
consistent (transitiveClosure x) == True
consistent (scc x)               == True
fmap consistent (toAcyclic x)    /= False
consistent (toAcyclicOrd x)      == True