{-# OPTIONS_GHC -Wall #-}
module Data.Graph.Good
( Graph
, graphFromEdges
, vertices
, edges
, outdegree
, indegree
, transposeG
, dfs
, dff
, topSort
, reverseTopSort
, components
, scc
, bcc
, reachable
, path
) where
import Control.Applicative (empty)
import Control.Arrow ((***))
import Control.Monad ((<=<))
import Data.Array (Ix, Array)
import qualified Data.Array as A
import qualified Data.Graph as G
import Data.Maybe (mapMaybe, fromMaybe)
data Graph v = Graph
{ g_graph :: G.Graph
, g_from_vert :: G.Vertex -> v
, g_to_vert :: v -> Maybe G.Vertex
}
graphFromEdges :: Ord v => [(v, [v])] -> Graph v
graphFromEdges vs =
let (g, v_func, l) = G.graphFromEdges $ fmap (\(v, es) -> (v, v, es)) vs
in Graph g (\vert -> let (v, _, _) = v_func vert in v) l
vertices :: Graph v -> [v]
vertices g = fromVertices g $ overGraph G.vertices g
edges :: Graph v -> [(v, v)]
edges g = fmap (g_from_vert g *** g_from_vert g) $ overGraph G.edges g
overGraph :: (G.Graph -> r) -> Graph v -> r
overGraph f = f . g_graph
lookupArr :: Ix k => Array k v -> k -> Maybe v
lookupArr arr ix =
let (lo, hi) = A.bounds arr
in case (lo <= ix && ix <= hi) of
True -> Just $ arr A.! ix
False -> Nothing
outdegree :: Graph v -> v -> Maybe Int
outdegree g = lookupArr arr <=< g_to_vert g
where
arr = overGraph G.outdegree g
indegree :: Graph v -> v -> Maybe Int
indegree g = lookupArr arr <=< g_to_vert g
where
arr = overGraph G.indegree g
transposeG :: Graph v -> Graph v
transposeG g = g { g_graph = overGraph G.transposeG g }
fromVertices :: Functor f => Graph v -> f G.Vertex -> f v
fromVertices = fmap . g_from_vert
dfs :: Graph v -> [v] -> G.Forest v
dfs g vs =
let verts = mapMaybe (g_to_vert g) vs
in fmap (fromVertices g) $ overGraph G.dfs g verts
dff :: Graph v -> G.Forest v
dff g = fmap (fromVertices g) $ overGraph G.dff g
topSort :: Graph v -> [v]
topSort g = fromVertices g $ overGraph G.topSort g
reverseTopSort :: Graph v -> [v]
reverseTopSort = reverse . topSort
components :: Graph v -> G.Forest v
components g = fmap (fromVertices g) $ overGraph G.components g
scc :: Graph v -> G.Forest v
scc g = fmap (fromVertices g) $ overGraph G.scc g
bcc :: Graph v -> G.Forest [v]
bcc g = fmap (fmap $ fromVertices g) $ overGraph G.bcc g
reachable :: Graph v -> v -> [v]
reachable g v = case g_to_vert g v of
Nothing -> empty
Just vert -> fromVertices g $ overGraph G.reachable g vert
path :: Graph v -> v -> v -> Bool
path g v1 v2 = fromMaybe False $ do
vert1 <- g_to_vert g v1
vert2 <- g_to_vert g v2
pure $ overGraph G.path g vert1 vert2