hydra-0.5.0: src/main/haskell/Hydra/Tools/Sorting.hs
-- | Utilities for sorting
module Hydra.Tools.Sorting (
topologicalSort,
topologicalSortComponents,
initGraph
) where
import qualified Data.List as L
import qualified Data.Bifunctor as BF
import qualified Data.Graph as G
-- | Sort a directed acyclic graph (DAG) based on an adjacency list
-- Yields a list of nontrivial strongly connected components if the graph has cycles
topologicalSort :: Ord a => [(a, [a])] -> Either [[a]] [a]
topologicalSort pairs = if L.null withCycles
then Right $ L.concat sccs
else Left withCycles
where
sccs = topologicalSortComponents pairs
withCycles = L.filter isCycle sccs
isCycle = not . L.null . L.tail
-- | Find the strongly connected components (including cycles and isolated vertices) of a graph, in (reverse) topological order
topologicalSortComponents :: Ord a => [(a, [a])] -> [[a]]
topologicalSortComponents pairs = L.sort <$> (fmap (getKey nodeFromVertex) . treeToList) <$> G.scc g
where
(g, nodeFromVertex) = initGraph pairs
treeToList :: G.Tree a -> [a]
treeToList (G.Node root subforest) = root:(L.concat (treeToList <$> subforest))
getKey :: (G.Vertex -> ((), a, [a])) -> G.Vertex -> a
getKey nodeFromVertex v = n
where
(_, n, _) = nodeFromVertex v
initGraph :: Ord a => [(a, [a])] -> (G.Graph, G.Vertex -> ((), a, [a]))
initGraph pairs = (g, nodeFromVertex)
where
(g, nodeFromVertex, _) = G.graphFromEdges (toEdge <$> pairs)
toEdge (key, keys) = ((), key, keys)