packages feed

graph-wrapper 0.1 → 0.1.1

raw patch · 2 files changed

+67/−8 lines, 2 filesdep ~containersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: containers

API changes (from Hackage documentation)

- Data.Graph.Wrapper: instance (Show i) => Show (SCC i)
+ Data.Graph.Wrapper: depthNumbering :: Ord i => Graph i v -> [i] -> Graph i (v, Maybe Int)
+ Data.Graph.Wrapper: instance Show i => Show (SCC i)
- Data.Graph.Wrapper: fromList :: (Ord i) => [(i, v, [i])] -> Graph i v
+ Data.Graph.Wrapper: fromList :: Ord i => [(i, v, [i])] -> Graph i v
- Data.Graph.Wrapper: fromListBy :: (Ord i) => (v -> i) -> [(v, [i])] -> Graph i v
+ Data.Graph.Wrapper: fromListBy :: Ord i => (v -> i) -> [(v, [i])] -> Graph i v
- Data.Graph.Wrapper: fromListSimple :: (Ord v) => [(v, [v])] -> Graph v v
+ Data.Graph.Wrapper: fromListSimple :: Ord v => [(v, [v])] -> Graph v v
- Data.Graph.Wrapper: fromVerticesEdges :: (Ord i) => [(i, v)] -> [Edge i] -> Graph i v
+ Data.Graph.Wrapper: fromVerticesEdges :: Ord i => [(i, v)] -> [Edge i] -> Graph i v
- Data.Graph.Wrapper: hasPath :: (Ord i) => Graph i v -> Edge i -> Bool
+ Data.Graph.Wrapper: hasPath :: Ord i => Graph i v -> i -> i -> Bool
- Data.Graph.Wrapper: indegree :: (Ord i) => Graph i v -> i -> Int
+ Data.Graph.Wrapper: indegree :: Ord i => Graph i v -> i -> Int
- Data.Graph.Wrapper: outdegree :: (Ord i) => Graph i v -> i -> Int
+ Data.Graph.Wrapper: outdegree :: Ord i => Graph i v -> i -> Int
- Data.Graph.Wrapper: reachableVertices :: (Ord i) => Graph i v -> i -> [i]
+ Data.Graph.Wrapper: reachableVertices :: Ord i => Graph i v -> i -> [i]
- Data.Graph.Wrapper: sccGraph :: (Ord i) => Graph i v -> Graph (Set i) (Map i v)
+ Data.Graph.Wrapper: sccGraph :: Ord i => Graph i v -> Graph (Set i) (Map i v)
- Data.Graph.Wrapper: successors :: (Ord i) => Graph i v -> i -> [i]
+ Data.Graph.Wrapper: successors :: Ord i => Graph i v -> i -> [i]
- Data.Graph.Wrapper: vertex :: (Ord i) => Graph i v -> i -> v
+ Data.Graph.Wrapper: vertex :: Ord i => Graph i v -> i -> v

Files

Data/Graph/Wrapper.hs view
@@ -24,15 +24,19 @@          reachableVertices, hasPath,     -    topologicalSort,+    topologicalSort, depthNumbering,          SCC(..), stronglyConnectedComponents, sccGraph   ) where  import Control.Arrow (second)+import Control.Monad+import Control.Monad.ST  import Data.Array+import Data.Array.ST import qualified Data.Graph as G+import qualified Data.IntSet as IS import Data.List (sortBy, mapAccumL) import Data.Maybe (fromMaybe, fromJust) import qualified Data.Map as M@@ -53,6 +57,15 @@ thd3 (_, _, c) = c  +-- amapWithKey :: Ix i => (i -> v -> v') -> Array i v -> Array i v'+-- -- More efficient, but not portable (uses GHC.Arr exports):+-- --amapWithKey f arr = unsafeArray' (bounds arr) (numElements arr) [(i, f i (unsafeAt arr i)) | i <- [0 .. n - 1]]+-- amapWithKey f arr = array (bounds arr) [(i, f i v) | (i, v) <- assocs arr]++amapWithKeyM :: (Monad m, Ix i) => (i -> v -> m v') -> Array i v -> m (Array i v')+amapWithKeyM f arr = liftM (array (bounds arr)) $ mapM (\(i, v) -> liftM (\v' -> (i, v')) $ f i v) (assocs arr)++ -- | An edge from the first vertex to the second type Edge i = (i, i) @@ -76,9 +89,14 @@     traverse f g = fmap (\gvva -> g { gVertexVertexArray = gvva }) (Traversable.traverse f (gVertexVertexArray g))  +{-# RULES "indexGVertex/gVertexIndex" forall g i. gVertexIndex g (indexGVertex g i) = i #-}+{-# RULES "gVertexIndex/indexGVertex" forall g v. indexGVertex g (gVertexIndex g v) = v #-}++{-# NOINLINE [0] indexGVertex #-} indexGVertex :: Ord i => Graph i v -> i -> G.Vertex indexGVertex g i = indexGVertex' (indexGVertexArray g) i +{-# NOINLINE [0] gVertexIndex #-} gVertexIndex :: Graph i v -> G.Vertex -> i gVertexIndex g gv = indexGVertexArray g ! gv @@ -175,7 +193,7 @@ -- | Topological sort of of the graph (<http://en.wikipedia.org/wiki/Topological_sort>). If the graph is acyclic, -- vertices will only appear in the list once all of those vertices with arrows to them have already appeared. ----- Vertex i precedes j in the output whenever j is reachable from i but not vice versa.+-- Vertex /i/ precedes /j/ in the output whenever /j/ is reachable from /i/ but not vice versa. topologicalSort :: Graph i v -> [i] topologicalSort g = map (gVertexIndex g) $ G.topSort (graph g) @@ -184,10 +202,51 @@ reachableVertices g = map (gVertexIndex g) . G.reachable (graph g) . indexGVertex g  -- | Is the second vertex reachable by following edges from the first vertex?-hasPath :: Ord i => Graph i v -> Edge i -> Bool-hasPath g (i1, i2) = G.path (graph g) (indexGVertex g i1) (indexGVertex g i2)+--+-- It is worth sharing a partial application of 'hasPath' to the first vertex if you are testing for several+-- vertices being reachable from it.+hasPath :: Ord i => Graph i v -> i -> i -> Bool+hasPath g i1 = (`elem` reachableVertices g i1) +-- | Number the vertices in the graph by how far away they are from the given roots. The roots themselves have depth 0,+-- and every subsequent link we traverse adds 1 to the depth. If a vertex is not reachable it will have a depth of 'Nothing'.+depthNumbering :: Ord i => Graph i v -> [i] -> Graph i (v, Maybe Int)+depthNumbering g is = runST $ do+    -- This array records the minimum known depth for the node at the moment+    depth_array <- newArray (bounds (graph g)) Nothing :: ST s (STArray s G.Vertex (Maybe Int))+    let -- Lets us adjust the known depth given a new observation+        atDepth gv depth = do+            mb_old_depth <- readArray depth_array gv+            let depth' = maybe depth (`min` depth) mb_old_depth+            depth' `seq` writeArray depth_array gv (Just depth') +    -- Do an depth-first search on the graph (checking for cycles to prevent non-termination),+    -- recording the depth at which any node was seen in that array.+    let gos seen depth gvs = mapM_ (go seen depth) gvs++        go seen depth gv +          | depth `seq` False = error "depthNumbering: unreachable"+          | gv `IS.member` seen = return ()+          | otherwise = do+            gv `atDepth` depth+            gos (IS.insert gv seen) (depth + 1) (graph g ! gv)+    gos IS.empty 0 (map (indexGVertex g) is)+    +    -- let go _    _     []  = return ()+    --     go seen depth gvs = do+    --         let go_one (seen, next_gvs) gv+    --               | gv `IS.member` seen = return (seen, next_gvs)+    --               | otherwise = do gv `atDepth` depth+    --                                return (IS.insert gv seen, next_gvs ++ (graph g ! gv))+    --         (seen, next_gvs) <- foldM go_one (seen, []) gvs+    --         go seen (depth + 1) next_gvs+    -- +    -- go IS.empty 0 (map (indexGVertex g) is)+    +    gvva <- amapWithKeyM (\gv v -> liftM (\mb_depth -> (v, mb_depth)) $ readArray depth_array gv) (gVertexVertexArray g)+    return $ g { gVertexVertexArray = gvva }++ data SCC i = AcyclicSCC i            | CyclicSCC [i]            deriving (Show)@@ -212,8 +271,8 @@ --   1) Within the SCC itself (in the case of a 'CyclicSCC' only) --   2) Or from a node in a SCC later on in the list ----- Vertex i strictly precedes j in the output whenever i is reachable from j but not vice versa.--- Vertex i occurs in the same SCC as j whenever both i is reachable from j and j is reachable from i.+-- Vertex /i/ strictly precedes /j/ in the output whenever /i/ is reachable from /j/ but not vice versa.+-- Vertex /i/ occurs in the same SCC as /j/ whenever both /i/ is reachable from /j/ and /j/ is reachable from /i/. stronglyConnectedComponents :: Graph i v -> [SCC i] stronglyConnectedComponents g = map decode forest   where
graph-wrapper.cabal view
@@ -1,7 +1,7 @@ Cabal-Version:      >= 1.2 Build-Type:         Simple Name:               graph-wrapper-Version:            0.1+Version:            0.1.1 Maintainer:         Max Bolingbroke <batterseapower@hotmail.com> Homepage:           http://www.github.com/batterseapower/graph-wrapper License:            BSD3@@ -15,4 +15,4 @@          Build-Depends:      base >= 3.0 && < 5.0,                         array >= 0.3 && < 0.4,-                        containers >= 0.3 && < 0.4+                        containers >= 0.3 && < 0.5