packages feed

labeled-graph (empty) → 1.0.0.0

raw patch · 4 files changed

+554/−0 lines, 4 filesdep +basedep +labeled-treesetup-changed

Dependencies added: base, labeled-tree

Files

+ Data/LabeledGraph.hs view
@@ -0,0 +1,511 @@+{-# LANGUAGE ScopedTypeVariables #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.LabeledGraph+-- Copyright   :  (c) The University of Glasgow 2002, Jean-Philippe Bernardy 2012+-- License     :  BSD-style+--+-- Maintainer  :  JP Bernardy+-- Stability   :  experimental+-- Portability :  GHC+--+-- A version of the graph algorithms described in:+--+--   /Structuring Depth-First Search Algorithms in Haskell/,+--   by David King and John Launchbury.+--+--   Adapted to labeled graphs by JP Bernardy.+--+-----------------------------------------------------------------------------++module Data.Graph{-(++        -- * External interface++        -- At present the only one with a "nice" external interface+        stronglyConnComp, stronglyConnCompR, SCC(..), flattenSCC, flattenSCCs,++        -- * Graphs++        Graph, Table, Bounds, Edge, Vertex,++        -- ** Building graphs++        graphFromEdges, graphFromEdges', buildG, transposeG,+        -- reverseE,++        -- ** Graph properties++        vertices, edges,+        outdegree, indegree,++        -- * Algorithms++        dfs, dff,+        topSort,+        components,+        scc,+        bcc,+        -- tree, back, cross, forward,+        reachable, path,++        module Data.LabeledTree++    ) -} where++import Control.Monad.ST+import Data.Array.ST (STArray, newArray, readArray, writeArray)+import Data.LabeledTree (Tree(Node), Forest, (::>)((::>)) )++import Data.STRef++import Control.DeepSeq (NFData(rnf))+import Data.Maybe+import Data.Array+import Data.List+import qualified Data.Map as M+++-------------------------------------------------------------------------+--                                                                      -+--      External interface+--                                                                      -+-------------------------------------------------------------------------+{-+-- | Strongly connected component.+data SCC vertex = AcyclicSCC vertex     -- ^ A single vertex that is not+                                        -- in any cycle.+                | CyclicSCC  [vertex]   -- ^ A maximal set of mutually+                                        -- reachable vertices.++instance NFData a => NFData (SCC a) where+    rnf (AcyclicSCC v) = rnf v+    rnf (CyclicSCC vs) = rnf vs++-- | The vertices of a list of strongly connected components.+flattenSCCs :: [SCC a] -> [a]+flattenSCCs = concatMap flattenSCC++-- | The vertices of a strongly connected component.+flattenSCC :: SCC vertex -> [vertex]+flattenSCC (AcyclicSCC v) = [v]+flattenSCC (CyclicSCC vs) = vs++-- | The strongly connected components of a directed graph, topologically+-- sorted.+stronglyConnComp+        :: Ord key+        => [(node, key, [key])]+                -- ^ The graph: a list of nodes uniquely identified by keys,+                -- with a list of keys of nodes this node has edges to.+                -- The out-list may contain keys that don't correspond to+                -- nodes of the graph; such edges are ignored.+        -> [SCC node]++stronglyConnComp edges0+  = map get_node (stronglyConnCompR edges0)+  where+    get_node (AcyclicSCC (n, _, _)) = AcyclicSCC n+    get_node (CyclicSCC triples)     = CyclicSCC [n | (n,_,_) <- triples]++-- | The strongly connected components of a directed graph, topologically+-- sorted.  The function is the same as 'stronglyConnComp', except that+-- all the information about each node retained.+-- This interface is used when you expect to apply 'SCC' to+-- (some of) the result of 'SCC', so you don't want to lose the+-- dependency information.+stronglyConnCompR+        :: Ord key+        => [(node, key, [key])]+                -- ^ The graph: a list of nodes uniquely identified by keys,+                -- with a list of keys of nodes this node has edges to.+                -- The out-list may contain keys that don't correspond to+                -- nodes of the graph; such edges are ignored.+        -> [SCC (node, key, [key])]     -- ^ Topologically sorted++stronglyConnCompR [] = []  -- added to avoid creating empty array in graphFromEdges -- SOF+stronglyConnCompR edges0+  = map decode forest+  where+    (graph, vertex_fn,_) = graphFromEdges edges0+    forest             = scc graph+    decode (Node v []) | mentions_itself v = CyclicSCC [vertex_fn v]+                       | otherwise         = AcyclicSCC (vertex_fn v)+    decode other = CyclicSCC (dec other [])+                 where+                   dec (Node v ts) vs = vertex_fn v : foldr dec vs ts+    mentions_itself v = v `elem` (graph ! v)+-}+-------------------------------------------------------------------------+--                                                                      -+--      Graphs+--                                                                      -+-------------------------------------------------------------------------++-- | Abstract representation of vertices.+type Vertex  = Int+-- | Table indexed by a contiguous set of vertices.+type Table a = Array Vertex a+-- | Adjacency list representation of a graph, mapping each vertex to its+-- list of successors.+type Graph e  = Table [(e,Vertex)]+-- | The bounds of a 'Table'.+type Bounds  = (Vertex, Vertex)+-- | An edge from the first vertex to the second.+type Edge e  = (Vertex,e,Vertex)+++-- | Graph structure + colour on the vertices+data ColouredGraph c e = ColouredGraph (Graph e) (Colouring c)+type Colouring a = Vertex -> a+++showWithColor gr color = concat $ map showNode $ range $ bounds gr+    where showNode n =  show n ++ ": " ++ show (color n) ++ " -> " ++ show (gr!n) ++ "\n"++showDotFile gr = +    "digraph name {\n" +++    "rankdir=LR;\n" +++    (concatMap showEdge $ edges gr) +++    "}\n"+    where showEdge (from, t, to) = show from ++ " -> " ++ show to +++				   " [label = \"" ++ show t ++ "\"];\n"+++instance (Show c, Show e) => Show (ColouredGraph c e) where+    show (ColouredGraph gr col) = showWithColor gr col+++-- | All vertices of a graph.+vertices :: Graph l -> [Vertex]+vertices  = indices++-- | All edges of a graph.+edges    :: Graph e -> [Edge e]+edges g   = [ (v,l,w) | v <- vertices g, (l,w) <- g!v ]+++mapT    :: (Vertex -> a -> b) -> Table a -> Table b+mapT f t = array (bounds t) [ (,) v (f v (t!v)) | v <- indices t ]++-- | Build a graph from a list of edges.+buildG :: Bounds -> [Edge e] -> Graph e+buildG bounds0 edges0 = accumArray (flip (:)) [] bounds0 [(v, (l,w)) | (v,l,w) <- edges0]++-- | The graph obtained by reversing all edges.+transposeG  :: Graph e -> Graph e+transposeG g = buildG (bounds g) (reverseE g)++reverseE    :: Graph e -> [Edge e]+reverseE g   = [ (w, l, v) | (v, l, w) <- edges g ]++-- | Reverse all the edges of a graph+reverseG    :: Graph e -> Graph e+reverseG g   = buildG (bounds g) (reverseE g)+++-- | A table of the count of edges from each node.+outdegree :: Graph e -> Table Int+outdegree  = mapT numEdges+             where numEdges _ ws = length ws++-- | A table of the count of edges into each node.+indegree :: Graph e -> Table Int+indegree  = outdegree . transposeG++-- | Identical to 'graphFromEdges', except that the return value+-- does not include the function which maps keys to vertices.  This+-- version of 'graphFromEdges' is for backwards compatibility.+graphFromEdges'+        :: Ord key+        => [(node, key, [(e,key)])]+        -> (Graph e, Vertex -> (node, key, [(e,key)]))+graphFromEdges' x = (a,b) where+    (a,b,_) = graphFromEdges x++-- | Build a graph from a list of nodes uniquely identified by keys,+-- with a list of keys of nodes this node should have edges to.+-- The out-list may contain keys that don't correspond to+-- nodes of the graph; they are ignored.+graphFromEdges+        :: forall key e node. +           Ord key+        => [(node, key, [(e,key)])]+        -> (Graph e, Vertex -> (node, key, [(e,key)]), key -> Maybe Vertex)+graphFromEdges edges0+  = (graph, \v -> vertex_map ! v, key_vertex)+  where+    max_v           = length edges0 - 1+    bounds0         = (0,max_v) :: (Vertex, Vertex)+    sorted_edges    = sortBy lt edges0+    edges1          = zipWith (,) [0..] sorted_edges++    graph :: Graph e+    graph           = array bounds0 [(,) v [(e,v') | (e,k) <- ks, let Just v' = key_vertex k] +                                    | (,) v (_,    _, ks) <- edges1]+    key_map         = array bounds0 [(,) v k                        | (,) v (_,    k, _ ) <- edges1]+    vertex_map      = array bounds0 edges1++    (_,k1,_) `lt` (_,k2,_) = k1 `compare` k2++    key_vertex :: key -> Maybe Vertex+    --  returns Nothing for non-interesting vertices+    key_vertex k   = findVertex 0 max_v+                   where+                     findVertex a b | a > b+                              = Nothing+                     findVertex a b = case compare k (key_map ! mid) of+                                   LT -> findVertex a (mid-1)+                                   EQ -> Just mid+                                   GT -> findVertex (mid+1) b+                              where+                                mid = (a + b) `div` 2+                                +-------------------------------------------------------------------------+--                                                                      -+--      Depth first search+--                                                                      -+-------------------------------------------------------------------------++-- | A spanning forest of the graph, obtained from a depth-first search of+-- the graph starting from each vertex in an unspecified order.+dff          :: Graph e -> [Tree e Vertex]+dff g         = dfs g (vertices g)++-- | A spanning forest of the part of the graph reachable from the listed+-- vertices, obtained from a depth-first search of the graph starting at+-- each of the listed vertices in order.+dfs          :: Graph e -> [Vertex] -> [Tree e Vertex]+dfs g vs      = map dropLabel $ prune (bounds g) (map (\v -> error "dfs: no top-level label" ::> generate g v) vs)++dropLabel ~(_ ::> t) = t+++generate     :: Graph e -> Vertex -> Tree e Vertex+generate g v  = Node v [e ::> generate g v' | (e,v') <- g!v]++prune        :: Bounds -> Forest e Vertex -> Forest e Vertex+prune bnds ts = run bnds (chop ts)++chop         :: Forest e Vertex -> SetM s (Forest e Vertex)+chop []       = return []+chop ((e ::> Node v ts) : us)+              = do+                visited <- contains v+                if visited then+                  chop us+                 else do+                  include v+                  as <- chop ts+                  bs <- chop us+                  return ((e ::> Node v as) : bs)++-- A monad holding a set of vertices visited so far.+-- Use the ST for constant-time primitives.++newtype SetM s a = SetM { runSetM :: STArray s Vertex Bool -> ST s a }++instance Monad (SetM s) where+    return x     = SetM $ const (return x)+    SetM v >>= f = SetM $ \ s -> do { x <- v s; runSetM (f x) s }++run          :: Bounds -> (forall s. SetM s a) -> a+run bnds act  = runST (newArray bnds False >>= runSetM act)++contains     :: Vertex -> SetM s Bool+contains v    = SetM $ \ m -> readArray m v++include      :: Vertex -> SetM s ()+include v     = SetM $ \ m -> writeArray m v True+++-------------------------------------------------------------------------+--                                                                      -+--      Algorithms+--                                                                      -+-------------------------------------------------------------------------++------------------------------------------------------------+-- Algorithm 1: depth first search numbering+------------------------------------------------------------++type DList a = a -> a++dconcat :: [DList a] -> DList a+dconcat = foldr (.) id ++preorder' :: [e] -> Tree e a -> DList [(a,[e])]+preorder' es (Node a ts) = ((a,es) :) . preorderF' es ts++preorderF' :: [e] -> Forest e a -> DList [(a,[e])] +preorderF' es ts = dconcat [ preorder' (e : es) t | (e ::> t) <- ts]++second f (a,b) = (a,f b)++preorderF :: [Tree e a] -> [(a,[e])]+preorderF ts = dconcat [ preorder' [] t | t <- ts] []++tabulate        :: Bounds -> [Vertex] -> Table Int+tabulate bnds vs = array bnds (zipWith (,) vs [1..])+++preArr          :: Bounds -> [Tree e Vertex] -> Table Int+preArr bnds      = tabulate bnds . map fst . preorderF++------------------------------------------------------------+-- Algorithm 2: topological sorting+------------------------------------------------------------++postorder :: Tree e a -> [a] -> [a]+postorder (Node a ts) = postorderF (map dropLabel ts) . (a :)++postorderF   :: [Tree e a] -> [a] -> [a]+postorderF ts = foldr (.) id $ map postorder ts++postOrd :: Graph e -> [Vertex]+postOrd g = postorderF (dff g) []++-- | A topological sort of the graph.+-- The order is partially specified by the condition that a vertex /i/+-- precedes /j/ whenever /j/ is reachable from /i/ but not vice versa.+topSort      :: Graph e -> [Vertex]+topSort       = reverse . postOrd++------------------------------------------------------------+-- Algorithm 3: connected components+------------------------------------------------------------++-- | The connected components of a graph.+-- Two vertices are connected if there is a path between them, traversing+-- edges in either direction.+components   :: Graph e -> [Tree e Vertex]+components    = dff . undirected++undirected   :: Graph e -> Graph e+undirected g  = buildG (bounds g) (edges g ++ reverseE g)++------------------------------------------------------------+-- Algorithm 4: strongly connected components+------------------------------------------------------------++-- | The strongly connected components of a graph.+scc  :: Graph e -> [Tree e Vertex]+scc g = dfs g (reverse (postOrd (transposeG g)))+++------------------------------------------------------------+-- Algorithm 6: Finding reachable vertices+------------------------------------------------------------++-- | A list of vertices reachable from a given vertex.+reachable    :: Graph e -> Vertex -> [(Vertex,[e])]+reachable g v = preorderF (dfs g [v])+++-- | Is the second vertex reachable from the first?+path         :: Graph e -> Vertex -> Vertex -> Bool+path g v w    = w `elem` map fst (reachable g v)++------------------------------------------------------------+-- Algorithm 7: Biconnected components+------------------------------------------------------------+{-+-- | The biconnected components of a graph.+-- An undirected graph is biconnected if the deletion of any vertex+-- leaves it connected.+bcc :: Graph -> Forest [Vertex]+bcc g = (concat . map bicomps . map (do_label g dnum)) forest+ where forest = dff g+       dnum   = preArr (bounds g) forest++do_label :: Graph e -> Table Int -> Tree e Vertex -> Tree e (Vertex,Int,Int)+do_label g dnum (Node v ts) = Node (v,dnum!v,lv) us+ where us = map (do_label g dnum) ts+       lv = minimum ([dnum!v] ++ [dnum!w | w <- g!v]+                     ++ [lu | Node (_,_,lu) _ <- us])++bicomps :: Tree (Vertex,Int,Int) -> Forest [Vertex]+bicomps (Node (v,_,_) ts)+      = [ Node (v:vs) us | (_,Node vs us) <- map collect ts]++collect :: Tree e (Vertex,Int,Int) -> (Int, Tree e [Vertex])+collect (Node (v,dv,lv) ts) = (lv, Node (v:vs) cs)+ where collected = map collect ts+       vs = concat [ ws | (lw, Node ws _) <- collected, lw<dv]+       cs = concat [ if lw<dv then us else [Node (v:ws) us]+                        | (lw, Node ws us) <- collected ]+            +            +-}+-------------+-- * Cycamore stuff++put ref item = + do l <- readSTRef ref+    writeSTRef ref (item:l)++allocId uidRef = +    do uid <- readSTRef uidRef+       writeSTRef uidRef (uid + 1)+       return uid++simpleGenerator f x = (x, f x)++unfoldManyST :: forall key edgeLabel colour stTag. (Ord key) => (key -> (colour, [(edgeLabel, key)]))+             -> [key] -> ST stTag ([Vertex], ColouredGraph colour edgeLabel)+unfoldManyST gen seeds =+     do mtab <- newSTRef M.empty+	allNodes <- newSTRef []+        uidRef <- newSTRef firstId+	let -- cyc :: a -> ST s Vertex+            cyc src = +	     do probe <- memTabFind mtab src+	        case probe of+  	         Just result -> return result+	         Nothing -> do+		     v <- allocId uidRef+		     memTabBind src v mtab +		     let (lab, deps) = gen src+		     ws <- mapM (cyc . snd) deps+		     let res = (v, lab, [(fst d, w) | d <- deps | w <- ws])+                     put allNodes res+		     return v+	mapM_ cyc seeds+	list <- readSTRef allNodes+	seedsResult <- (return . map fromJust) =<< mapM (memTabFind mtab) seeds+	lastId <- readSTRef uidRef+	let cycamore = array (firstId, lastId-1) [(i, k) | (i, a, k) <- list]+	let labels = array (firstId, lastId-1) [(i, a) | (i, a, k) <- list]+	return (seedsResult, ColouredGraph cycamore (labels!))+   where firstId = 0::Vertex+         memTabFind mt key = return . M.lookup key =<< readSTRef mt+         memTabBind key val mt = modifySTRef mt (M.insert key val)++unfold :: forall key edgeLabel colour stTag. (Ord key) => (key -> (colour, [(edgeLabel, key)]))+             -> key -> (Vertex, ColouredGraph colour edgeLabel)+unfold f r = (r', res)+  where ([r'], res) = unfoldMany f [r]++unfoldMany :: forall key edgeLabel colour stTag. (Ord key) => (key -> (colour, [(edgeLabel, key)]))+             -> [key] -> ([Vertex], ColouredGraph colour edgeLabel)+unfoldMany f roots = runST (unfoldManyST f roots)++fold' :: Eq c => c -> (Vertex -> [(b,c)] -> c) -> Graph b -> Vertex -> c+fold' z f gr v = scan' z f gr v++scan' :: Eq c => c -> (Vertex -> [(b,c)] -> c) -> Graph b -> Colouring c+scan' bot f gr = (finalTbl !)+    where finalTbl = fixedPoint updateTbl initialTbl+	  initialTbl = listArray bnds (replicate (rangeSize bnds) bot)+			   +	  fixedPoint f x = fp x+	      where fp z = if z == z' then z else fp z'+			where z' = f z+	  updateTbl tbl = listArray bnds $ map recompute $ vertices gr+	      where recompute v = f v [(b, tbl!k) | (b, k) <- gr!v]+          bnds = bounds gr++scan :: Eq c => c -> (a -> [(e,c)] -> c) -> ColouredGraph a e -> ColouredGraph c e+scan bot f (ColouredGraph gr a) = ColouredGraph gr (scan' bot f' gr)+    where f' v kids = f (a v) kids+
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) <year>, <copyright holder>+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright+      notice, this list of conditions and the following disclaimer in the+      documentation and/or other materials provided with the distribution.+    * Neither the name of the <organization> nor the+      names of its contributors may be used to endorse or promote products+      derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ labeled-graph.cabal view
@@ -0,0 +1,17 @@+name:       labeled-graph+version:    1.0.0.0+license:    BSD3+license-file:    LICENSE+maintainer:    jeanphilippe.bernardy@gmail.com+synopsis:   Labeled graph structure+category:   Data Structures+description:+        Labeled tree structure, on the model of the standard Data.Graph+build-type: Simple+cabal-version:  >=1.6++Library + build-depends: base >= 1 && < 6+ build-depends: labeled-tree >= 1 && < 1000+ exposed-modules:+  Data.LabeledGraph