graphite 0.2.1.0 → 0.3.0.0
raw patch · 9 files changed
+177/−105 lines, 9 filesdep +containersPVP ok
version bump matches the API change (PVP)
Dependencies added: containers
API changes (from Hackage documentation)
- Data.Graph.Connectivity: isDisconnected :: UGraph v e -> Bool
- Data.Graph.Connectivity: unreachableVertices :: UGraph v e -> [v]
- Data.Graph.DGraph: isIsolated :: DGraph v e -> Bool
- Data.Graph.Visualize: plotIO :: (Show e) => UGraph Int e -> FilePath -> IO FilePath
- Data.Graph.Visualize: plotXdgIO :: (Show e) => UGraph Int e -> FilePath -> IO ()
+ Data.Graph.Connectivity: isIsolated :: (Graph g, Hashable v, Eq v) => g v e -> v -> Bool
+ Data.Graph.Connectivity: isStronglyConnected :: (Hashable v, Eq v, Ord v) => DGraph v e -> Bool
+ Data.Graph.DGraph: toUndirected :: (Hashable v, Eq v) => DGraph v e -> UGraph v e
+ Data.Graph.Types: areAdjacent :: (Graph g, Hashable v, Eq v) => g v e -> v -> v -> Bool
+ Data.Graph.Types: directlyReachableVertices :: (Graph g, Hashable v, Eq v) => g v e -> v -> [v]
+ Data.Graph.Visualize: plotDirectedIO :: (Show e) => DGraph Int e -> FilePath -> IO FilePath
+ Data.Graph.Visualize: plotDirectedXdgIO :: (Show e) => DGraph Int e -> FilePath -> IO ()
+ Data.Graph.Visualize: plotUndirectedIO :: (Show e) => UGraph Int e -> FilePath -> IO FilePath
+ Data.Graph.Visualize: plotUndirectedXdgIO :: (Show e) => UGraph Int e -> FilePath -> IO ()
- Data.Graph.Connectivity: areConnected :: UGraph v e -> v -> v -> Bool
+ Data.Graph.Connectivity: areConnected :: forall g v e. (Graph g, Hashable v, Eq v, Ord v) => g v e -> v -> v -> Bool
- Data.Graph.Connectivity: areDisconnected :: UGraph v e -> v -> v -> Bool
+ Data.Graph.Connectivity: areDisconnected :: (Graph g, Hashable v, Eq v, Ord v) => g v e -> v -> v -> Bool
- Data.Graph.Connectivity: isConnected :: UGraph v e -> Bool
+ Data.Graph.Connectivity: isConnected :: (Hashable v, Eq v) => UGraph v e -> Bool
- Data.Graph.Connectivity: isWeaklyConnected :: DGraph v e -> Bool
+ Data.Graph.Connectivity: isWeaklyConnected :: (Hashable v, Eq v) => DGraph v e -> Bool
- Data.Graph.DGraph: removeArc :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e
+ Data.Graph.DGraph: removeArc :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e
- Data.Graph.DGraph: removeArc' :: (Hashable v, Eq v) => (v, v) -> DGraph v e -> DGraph v e
+ Data.Graph.DGraph: removeArc' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e
- Data.Graph.DGraph: removeArcAndVertices :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e
+ Data.Graph.DGraph: removeArcAndVertices :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e
- Data.Graph.DGraph: removeArcAndVertices' :: (Hashable v, Eq v) => (v, v) -> DGraph v e -> DGraph v e
+ Data.Graph.DGraph: removeArcAndVertices' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e
- Data.Graph.Types: insertEdgePair :: (Graph g, Hashable v, Eq v) => (v, v) -> g v () -> g v ()
+ Data.Graph.Types: insertEdgePair :: (Graph g, Hashable v, Eq v) => g v () -> (v, v) -> g v ()
- Data.Graph.Types: insertVertex :: (Graph g, Hashable v, Eq v) => v -> g v e -> g v e
+ Data.Graph.Types: insertVertex :: (Graph g, Hashable v, Eq v) => g v e -> v -> g v e
- Data.Graph.Types: insertVertices :: (Graph g, Hashable v, Eq v) => [v] -> g v e -> g v e
+ Data.Graph.Types: insertVertices :: (Graph g, Hashable v, Eq v) => g v e -> [v] -> g v e
- Data.Graph.Types: removeEdgePair :: (Graph g, Hashable v, Eq v) => (v, v) -> g v e -> g v e
+ Data.Graph.Types: removeEdgePair :: (Graph g, Hashable v, Eq v) => g v e -> (v, v) -> g v e
- Data.Graph.Types: removeEdgePairAndVertices :: (Graph g, Hashable v, Eq v) => (v, v) -> g v e -> g v e
+ Data.Graph.Types: removeEdgePairAndVertices :: (Graph g, Hashable v, Eq v) => g v e -> (v, v) -> g v e
- Data.Graph.UGraph: removeEdge :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e
+ Data.Graph.UGraph: removeEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e
- Data.Graph.UGraph: removeEdge' :: (Hashable v, Eq v) => (v, v) -> UGraph v e -> UGraph v e
+ Data.Graph.UGraph: removeEdge' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e
- Data.Graph.UGraph: removeEdgeAndVertices :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e
+ Data.Graph.UGraph: removeEdgeAndVertices :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e
- Data.Graph.UGraph: removeEdgeAndVertices' :: (Hashable v, Eq v) => (v, v) -> UGraph v e -> UGraph v e
+ Data.Graph.UGraph: removeEdgeAndVertices' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e
Files
- graphite.cabal +3/−2
- src/Data/Graph/Connectivity.hs +58/−25
- src/Data/Graph/DGraph.hs +28/−22
- src/Data/Graph/Generation.hs +9/−4
- src/Data/Graph/Types.hs +15/−5
- src/Data/Graph/UGraph.hs +17/−15
- src/Data/Graph/Visualize.hs +39/−24
- test/Data/Graph/DGraphSpec.hs +4/−4
- test/Data/Graph/UGraphSpec.hs +4/−4
graphite.cabal view
@@ -1,5 +1,5 @@ name: graphite-version: 0.2.1.0+version: 0.3.0.0 synopsis: Graphs and networks library description: Represent, analyze and visualize graphs homepage: https://github.com/alx741/graphite#readme@@ -23,10 +23,11 @@ , Data.Graph.Connectivity build-depends: base >= 4.7 && < 5 , hashable+ , containers+ , unordered-containers , random , process , graphviz- , unordered-containers , QuickCheck ghc-options: -Wall default-language: Haskell2010
src/Data/Graph/Connectivity.hs view
@@ -1,45 +1,76 @@ -- | For Connectivity analisis purposes a 'DGraph' can be converted into a -- | 'UGraph' using 'toUndirected' +{-# LANGUAGE ScopedTypeVariables #-}+ module Data.Graph.Connectivity where -import Data.Graph.UGraph-import Data.Graph.DGraph+import Data.List (foldl') --- | Tell if a 'UGraph' is connected--- | An Undirected Graph is @connected@ when there is a path between every pair--- | of vertices-isConnected :: UGraph v e -> Bool-isConnected = undefined+import Data.Hashable+import qualified Data.Set as S --- | Tell if a 'UGraph' is disconnected--- | An Undirected Graph is @disconnected@ when its not @connected@. See--- | 'isConnected'--- TODO: An edgeles graph with two or more vertices is disconnected-isDisconnected :: UGraph v e -> Bool-isDisconnected = not . isConnected+import Data.Graph.DGraph+import Data.Graph.Types+import Data.Graph.UGraph --- | Tell if two vertices of a 'UGraph' are connected+-- | Tell if two vertices of a graph are connected -- | Two vertices are @connected@ if it exists a path between them-areConnected :: UGraph v e -> v -> v -> Bool-areConnected = undefined+-- | The order of the vertices is relevant when the graph is directed+areConnected :: forall g v e . (Graph g, Hashable v, Eq v, Ord v)+ => g v e+ -> v+ -> v+ -> Bool+areConnected g fromV toV+ | fromV == toV = True+ | otherwise = search (directlyReachableVertices g fromV) S.empty toV+ where+ search :: [v] -> S.Set v -> v -> Bool+ search [] _ _ = False+ search (v:vs) banned v'+ | v `S.member` banned = search vs banned v'+ | v == v' = True+ | otherwise =+ search (directlyReachableVertices g v) banned' v'+ || search vs banned' v'+ where banned' = v `S.insert` banned -- | Tell if two vertices of a 'UGraph' are disconnected -- | Two vertices are @disconnected@ if it doesn't exist a path between them-areDisconnected :: UGraph v e -> v -> v -> Bool-areDisconnected = undefined+areDisconnected :: (Graph g, Hashable v, Eq v, Ord v) => g v e -> v -> v -> Bool+areDisconnected g fromV toV = not $ areConnected g fromV toV --- | Retrieve all the unreachable vertices of a 'UGraph'--- | The @unreachable vertices@ are those with no adjacent 'Edge's-unreachableVertices :: UGraph v e -> [v]-unreachableVertices = undefined+-- | Tell if a vertex is isolated+-- | A vertex is @isolated@ if it has no incidet edges, that is, it has a degree+-- | of zero+isIsolated :: (Graph g, Hashable v, Eq v) => g v e -> v -> Bool+isIsolated g v = vertexDegree g v == 0 +-- | Tell if a graph is connected+-- | An Undirected Graph is @connected@ when there is a path between every pair+-- | of vertices+isConnected :: (Hashable v, Eq v) => UGraph v e -> Bool+isConnected g = foldl' (\b v -> b && (not $ isIsolated g v)) True $ vertices g+ -- | Tell if a 'DGraph' is weakly connected--- | A Directed Graph is @weakly connected@ if the equivalent undirected graph+-- | A Directed Graph is @weakly connected@ if the underlying undirected graph -- | is @connected@-isWeaklyConnected :: DGraph v e -> Bool-isWeaklyConnected = undefined -- isConnected . toUndirected+isWeaklyConnected :: (Hashable v, Eq v) => DGraph v e -> Bool+isWeaklyConnected = isConnected . toUndirected +-- | Tell if a 'DGraph' is strongly connected+-- | A Directed Graph is @strongly connected@ if it contains a directed path+-- | on every pair of vertices+isStronglyConnected :: (Hashable v, Eq v, Ord v) => DGraph v e -> Bool+isStronglyConnected g = go vs True+ where+ vs = vertices g+ go _ False = False+ go [] bool = bool+ go (v':vs') bool =+ go vs' $ foldl' (\b v -> b && (areConnected g v v')) bool vs+ -- TODO -- * connected component -- * strong components@@ -55,3 +86,5 @@ -- * super-connectivity -- * hyper-connectivity -- * Menger's theorem++-- Robin's Theorem: a graph is orientable if it is connected and has no bridges
src/Data/Graph/DGraph.hs view
@@ -9,7 +9,8 @@ import qualified Data.HashMap.Lazy as HM import Test.QuickCheck -import Data.Graph.Types+import Data.Graph.Types+import qualified Data.Graph.UGraph as UG -- | Directed Graph of Vertices in /v/ and Arcs with attributes in /e/ newtype DGraph v e = DGraph { unDGraph :: HM.HashMap v (Links v e) }@@ -22,17 +23,22 @@ edgePairs = arcs' containsVertex (DGraph g) = flip HM.member g- adjacentVertices = undefined+ areAdjacent (DGraph g) v1 v2 =+ HM.member v2 (getLinks v1 g) || HM.member v1 (getLinks v2 g)+ adjacentVertices g v = filter+ (\v' -> containsArc' g (v, v') || containsArc' g (v', v))+ (vertices g)+ directlyReachableVertices (DGraph g) v = v : (HM.keys $ getLinks v g) -- | The total number of inbounding and outbounding 'Arc's of a vertex vertexDegree g v = vertexIndegree g v + vertexOutdegree g v - insertVertex v (DGraph g) = DGraph $ hashMapInsert v HM.empty g- insertVertices vs g = foldl' (flip insertVertex) g vs+ insertVertex (DGraph g) v = DGraph $ hashMapInsert v HM.empty g+ insertVertices = foldl' insertVertex containsEdgePair = containsArc' incidentEdgePairs g v = fmap toPair $ incidentArcs g v- insertEdgePair (v1, v2) g = insertArc (Arc v1 v2 ()) g+ insertEdgePair g (v1, v2) = insertArc (Arc v1 v2 ()) g removeEdgePair = removeArc' removeEdgePairAndVertices = removeArcAndVertices' @@ -54,7 +60,7 @@ removeVertex :: (Hashable v, Eq v) => v -> DGraph v e -> DGraph v e removeVertex v g = DGraph $ (\(DGraph g') -> HM.delete v g')- $ foldl' (flip removeArc) g $ incidentArcs g v+ $ foldl' removeArc g $ incidentArcs g v -- | @O(log n)@ Insert a directed 'Arc' into a 'DGraph' -- | The involved vertices are inserted if don't exist. If the graph already@@ -62,7 +68,7 @@ insertArc :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e insertArc (Arc fromV toV edgeAttr) g = DGraph $ HM.adjust (insertLink toV edgeAttr) fromV g'- where g' = unDGraph $ insertVertices [fromV, toV] g+ where g' = unDGraph $ insertVertices g [fromV, toV] -- | @O(m*log n)@ Insert many directed 'Arc's into a 'DGraph' -- | Same rules as 'insertArc' are applied@@ -71,25 +77,25 @@ -- | @O(log n)@ Remove the directed 'Arc' from a 'DGraph' if present -- | The involved vertices are left untouched-removeArc :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e-removeArc = removeArc' . toPair+removeArc :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e+removeArc g = removeEdgePair g . toPair -- | Same as 'removeArc' but the arc is an ordered pair-removeArc' :: (Hashable v, Eq v) => (v, v) -> DGraph v e -> DGraph v e-removeArc' (v1, v2) (DGraph g) = case HM.lookup v1 g of+removeArc' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e+removeArc' (DGraph g) (v1, v2) = case HM.lookup v1 g of Nothing -> DGraph g Just v1Links -> DGraph $ HM.adjust (const v1Links') v1 g where v1Links' = HM.delete v2 v1Links -- | @O(log n)@ Remove the directed 'Arc' from a 'DGraph' if present -- | The involved vertices are also removed-removeArcAndVertices :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e-removeArcAndVertices = removeArcAndVertices' . toPair+removeArcAndVertices :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e+removeArcAndVertices g = removeEdgePairAndVertices g . toPair -- | Same as 'removeArcAndVertices' but the arc is an ordered pair-removeArcAndVertices' :: (Hashable v, Eq v) => (v, v) -> DGraph v e -> DGraph v e-removeArcAndVertices' (v1, v2) g =- removeVertex v2 $ removeVertex v1 $ removeArc' (v1, v2) g+removeArcAndVertices' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e+removeArcAndVertices' g (v1, v2) =+ removeVertex v2 $ removeVertex v1 $ removeEdgePair g (v1, v2) -- | @O(n*m)@ Retrieve the 'Arc's of a 'DGraph' arcs :: forall v e . (Hashable v, Eq v) => DGraph v e -> [Arc v e]@@ -139,12 +145,6 @@ isOriented :: DGraph v e -> Bool isOriented = undefined --- | Tell if a 'DGraph' is isolated--- | A graph is @isolated@ if it has no edges, that is, it has a degree of 0--- | TODO: What if it has a loop?-isIsolated :: DGraph v e -> Bool-isIsolated = undefined- -- | Indegree of a vertex -- | The number of inbounding 'Arc's to a vertex vertexIndegree :: DGraph v e -> v -> Int@@ -189,6 +189,12 @@ -- | A vertex is a @internal@ when its neither a @source@ nor a @sink@ isInternal :: DGraph v e -> v -> Bool isInternal g v = not $ isSource g v || isSink g v++-- | Convert a directed 'DGraph' to an undirected 'UGraph' by converting all of+-- | its 'Arc's into 'Edge's+toUndirected :: (Hashable v, Eq v) => DGraph v e -> UG.UGraph v e+toUndirected g = UG.insertEdges (fmap arcToEdge $ arcs g) empty+ where arcToEdge (Arc fromV toV attr) = Edge fromV toV attr -- | Tell if a 'DegreeSequence' is a Directed Graphic -- | A @Directed Graphic@ is a Degree Sequence for wich a 'DGraph' exists
src/Data/Graph/Generation.hs view
@@ -22,12 +22,17 @@ go :: Graph g => [Int] -> Float -> g Int () -> IO (g Int ()) go [] _ g = return g go (v:vs) pv g = do- rnds <- randomRs (0.0, 1.0) <$> newStdGen+ rnds <- replicateM (length vs + 1) $ randomRIO (0.0, 1.0)+ flipDir <- randomRIO (True, False) let vs' = zip rnds vs- go vs pv $! (foldl' (putV pv v) g vs')+ let g' = insertVertex g v+ go vs pv $! (foldl' (putV pv v flipDir) g' vs') - putV :: Graph g => Float -> Int -> g Int () -> (Float, Int) -> g Int ()- putV pv v g (p', v') | p' < pv = insertEdgePair (v, v') g | otherwise = g+ putV :: Graph g => Float -> Int -> Bool -> g Int () -> (Float, Int) -> g Int ()+ putV pv v flipDir g (p', v')+ | p' < pv = insertEdgePair g pair+ | otherwise = g+ where pair = if flipDir then (v', v) else (v, v') -- | Generate a random square binary matrix -- | Useful for use with 'fromAdjacencyMatrix'
src/Data/Graph/Types.hs view
@@ -32,9 +32,19 @@ -- | Tell if a vertex exists in the graph containsVertex :: (Hashable v, Eq v) => g v e -> v -> Bool + -- | Tell if two vertices are adjacent+ areAdjacent :: (Hashable v, Eq v) => g v e -> v -> v -> Bool+ -- | Retrieve the adjacent vertices of a vertex adjacentVertices :: (Hashable v, Eq v) => g v e -> v -> [v] + -- | Retrieve the vertices that are directly reachable from a particular+ -- | vertex.+ -- | A vertex is @directly reachable@ to other if there is an edge that+ -- | connects @from@ one vertex @to@ the other+ -- | Every vertex is directly reachable from itself+ directlyReachableVertices :: (Hashable v, Eq v) => g v e -> v -> [v]+ -- | Total number of incident edges of a vertex vertexDegree :: (Hashable v, Eq v) => g v e -> v -> Int @@ -65,12 +75,12 @@ -- | Insert a vertex into a graph -- | If the graph already contains the vertex leave the graph untouched- insertVertex :: (Hashable v, Eq v) => v -> g v e -> g v e+ insertVertex :: (Hashable v, Eq v) => g v e -> v -> g v e -- | Insert a many vertices into a graph -- | New vertices are inserted and already contained vertices are left -- | untouched- insertVertices :: (Hashable v, Eq v) => [v] -> g v e -> g v e+ insertVertices :: (Hashable v, Eq v) => g v e -> [v] -> g v e -- | Tell if an edge exists in the graph containsEdgePair :: (Hashable v, Eq v) => g v e -> (v, v) -> Bool@@ -81,15 +91,15 @@ -- | Insert an edge into a graph -- | The involved vertices are inserted if don't exist. If the graph already -- | contains the edge, its attribute is updated- insertEdgePair :: (Hashable v, Eq v) => (v, v) -> g v () -> g v ()+ insertEdgePair :: (Hashable v, Eq v) => g v () -> (v, v) -> g v () -- | Remove the edge from a graph present -- | The involved vertices are left untouched- removeEdgePair :: (Hashable v, Eq v) => (v, v) -> g v e -> g v e+ removeEdgePair :: (Hashable v, Eq v) => g v e -> (v, v) -> g v e -- | Remove the edge from a graph if present -- | The involved vertices are also removed- removeEdgePairAndVertices :: (Hashable v, Eq v) => (v, v) -> g v e -> g v e+ removeEdgePairAndVertices :: (Hashable v, Eq v) => g v e -> (v, v) -> g v e -- | Tell if a graph is simple -- | A graph is @simple@ if it has no multiple edges nor loops
src/Data/Graph/UGraph.hs view
@@ -4,7 +4,7 @@ module Data.Graph.UGraph where -import Data.List (foldl', reverse, sort)+import Data.List (foldl', reverse, sort) import Data.Hashable import qualified Data.HashMap.Lazy as HM@@ -27,14 +27,16 @@ edgePairs g = toPair <$> edges g containsVertex (UGraph g) = flip HM.member g+ areAdjacent (UGraph g) v1 v2 = HM.member v2 $ getLinks v1 g adjacentVertices (UGraph g) v = HM.keys $ getLinks v g+ directlyReachableVertices g v = v : (adjacentVertices g v) vertexDegree (UGraph g) v = length $ HM.keys $ getLinks v g- insertVertex v (UGraph g) = UGraph $ hashMapInsert v HM.empty g- insertVertices vs g = foldl' (flip insertVertex) g vs+ insertVertex (UGraph g) v = UGraph $ hashMapInsert v HM.empty g+ insertVertices = foldl' insertVertex containsEdgePair = containsEdge' incidentEdgePairs g v = fmap toPair $ incidentEdges g v- insertEdgePair (v1, v2) g = insertEdge (Edge v1 v2 ()) g+ insertEdgePair g (v1, v2) = insertEdge (Edge v1 v2 ()) g removeEdgePair = removeEdge' removeEdgePairAndVertices = removeEdgeAndVertices' @@ -63,7 +65,7 @@ removeVertex :: (Hashable v, Eq v) => v -> UGraph v e -> UGraph v e removeVertex v g = UGraph $ (\(UGraph g') -> HM.delete v g')- $ foldl' (flip removeEdge) g $ incidentEdges g v+ $ foldl' removeEdge g $ incidentEdges g v -- | @O(log n)@ Insert an undirected 'Edge' into a 'UGraph' -- | The involved vertices are inserted if don't exist. If the graph already@@ -71,7 +73,7 @@ insertEdge :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e insertEdge (Edge v1 v2 edgeAttr) g = UGraph $ link v2 v1 $ link v1 v2 g' where- g' = unUGraph $ insertVertices [v1, v2] g+ g' = unUGraph $ insertVertices g [v1, v2] link fromV toV = HM.adjust (insertLink toV edgeAttr) fromV -- | @O(m*log n)@ Insert many directed 'Edge's into a 'UGraph'@@ -81,12 +83,12 @@ -- | @O(log n)@ Remove the undirected 'Edge' from a 'UGraph' if present -- | The involved vertices are left untouched-removeEdge :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e-removeEdge = removeEdgePair . toPair+removeEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e+removeEdge g = removeEdgePair g . toPair -- | Same as 'removeEdge' but the edge is an unordered pair-removeEdge' :: (Hashable v, Eq v) => (v, v) -> UGraph v e -> UGraph v e-removeEdge' (v1, v2) graph@(UGraph g)+removeEdge' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e+removeEdge' graph@(UGraph g) (v1, v2) | containsVertex graph v1 && containsVertex graph v2 = UGraph $ update v2Links v2 $ update v1Links v1 g | otherwise = UGraph g@@ -97,13 +99,13 @@ -- | @O(log n)@ Remove the undirected 'Edge' from a 'UGraph' if present -- | The involved vertices are also removed-removeEdgeAndVertices :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e-removeEdgeAndVertices = removeEdgePairAndVertices . toPair+removeEdgeAndVertices :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e+removeEdgeAndVertices g = removeEdgePairAndVertices g . toPair -- | Same as 'removeEdgeAndVertices' but the edge is an unordered pair-removeEdgeAndVertices' :: (Hashable v, Eq v) => (v, v) -> UGraph v e -> UGraph v e-removeEdgeAndVertices' (v1, v2) g =- removeVertex v2 $ removeVertex v1 $ removeEdgePair (v1, v2) g+removeEdgeAndVertices' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e+removeEdgeAndVertices' g (v1, v2) =+ removeVertex v2 $ removeVertex v1 $ removeEdgePair g (v1, v2) -- | @O(n*m)@ Retrieve the 'Edge's of a 'UGraph' edges :: forall v e . (Hashable v, Eq v) => UGraph v e -> [Edge v e]
src/Data/Graph/Visualize.hs view
@@ -1,40 +1,55 @@ module Data.Graph.Visualize- ( plotIO- , plotXdgIO+ ( plotUndirectedIO+ , plotUndirectedXdgIO++ , plotDirectedIO+ , plotDirectedXdgIO ) where import Data.GraphViz-import Data.GraphViz.Attributes.Complete import Data.Hashable-import Data.Monoid ((<>))+import Data.Monoid ((<>)) import System.Process -import qualified Data.Graph.UGraph as G-import Data.Graph.Types+import Data.Graph.DGraph+import Data.Graph.Types+import Data.Graph.UGraph -- | Plot an undirected 'UGraph' to a PNG image file-plotIO :: (Show e) => G.UGraph Int e -> FilePath -> IO FilePath-plotIO g fp = addExtension (runGraphvizCommand Sfdp $ toDot' g) Png fp+plotUndirectedIO :: (Show e) => UGraph Int e -> FilePath -> IO FilePath+plotUndirectedIO g fp = addExtension (runGraphvizCommand Sfdp $ toUndirectedDot g) Png fp --- | Same as 'plotIO' but open the resulting image with /xdg-open/-plotXdgIO :: (Show e) => G.UGraph Int e -> FilePath -> IO ()-plotXdgIO g fp = do- fp' <- plotIO g fp+-- | Same as 'plotUndirectedIO' but open the resulting image with /xdg-open/+plotUndirectedXdgIO :: (Show e) => UGraph Int e -> FilePath -> IO ()+plotUndirectedXdgIO g fp = do+ fp' <- plotUndirectedIO g fp _ <- system $ "xdg-open " <> fp' return () -labeledNodes :: (Show v) => G.UGraph v e -> [(v, String)]+-- | Plot a directed 'DGraph' to a PNG image file+plotDirectedIO :: (Show e) => DGraph Int e -> FilePath -> IO FilePath+plotDirectedIO g fp = addExtension (runGraphvizCommand Sfdp $ toDirectedDot g) Png fp++-- | Same as 'plotDirectedIO' but open the resulting image with /xdg-open/+plotDirectedXdgIO :: (Show e) => DGraph Int e -> FilePath -> IO ()+plotDirectedXdgIO g fp = do+ fp' <- plotDirectedIO g fp+ _ <- system $ "xdg-open " <> fp'+ return ()++labeledNodes :: (Graph g, Show v) => g v e -> [(v, String)] labeledNodes g = fmap (\v -> (v, show v)) $ vertices g -labeledEdges :: (Hashable v, Eq v, Show e) => G.UGraph v e -> [(v, v, String)]-labeledEdges g = fmap (\(Edge v1 v2 attr) -> (v1, v2, show attr)) $ G.edges g+labeledEdges :: (Hashable v, Eq v, Show e) => UGraph v e -> [(v, v, String)]+labeledEdges g = fmap (\(Edge v1 v2 attr) -> (v1, v2, show attr)) $ edges g -toDot' :: (Show e) => G.UGraph Int e -> DotGraph Int-toDot' g = graphElemsToDot params (labeledNodes g) (labeledEdges g)- where params = nonClusteredParams- { isDirected = False- , globalAttributes = [GraphAttrs- [ NodeSep 1, Overlap ScaleOverlaps- , Shape Circle- ]]- }+labeledArcs :: (Hashable v, Eq v, Show e) => DGraph v e -> [(v, v, String)]+labeledArcs g = fmap (\(Arc v1 v2 attr) -> (v1, v2, show attr)) $ arcs g++toUndirectedDot :: (Show e) => UGraph Int e -> DotGraph Int+toUndirectedDot g = graphElemsToDot params (labeledNodes g) (labeledEdges g)+ where params = nonClusteredParams { isDirected = False }++toDirectedDot :: (Show e) => DGraph Int e -> DotGraph Int+toDirectedDot g = graphElemsToDot params (labeledNodes g) (labeledArcs g)+ where params = nonClusteredParams { isDirected = True }
test/Data/Graph/DGraphSpec.hs view
@@ -10,8 +10,8 @@ spec = do describe "Directed Graph (DGraph)" $ do it "Can tell if a vertex exists" $ property $ do- let g = insertVertex 1 empty :: DGraph Int ()- let g' = insertVertex 2 empty :: DGraph Int ()+ let g = insertVertex empty 1 :: DGraph Int ()+ let g' = insertVertex empty 2 :: DGraph Int () containsVertex g 1 `shouldBe` True containsVertex g' 1 `shouldBe` False @@ -23,12 +23,12 @@ it "Increments its order when a new vertex is inserted" $ property $ \g v -> (not $ g `containsVertex` v)- ==> order g + 1 == order (insertVertex v (g :: DGraph Int ()))+ ==> order g + 1 == order (insertVertex (g :: DGraph Int ()) v) it "Increments its size when a new arc is inserted" $ property $ \g arc -> (not $ g `containsArc` arc) ==> size g + 1 == size (insertArc arc (g :: DGraph Int ())) it "Is id when inserting and removing a new vertex" $ property $ \g v -> (not $ g `containsVertex` v)- ==> ((removeVertex v . insertVertex v) g)+ ==> (removeVertex v $ insertVertex g v) == (g :: DGraph Int ())
test/Data/Graph/UGraphSpec.hs view
@@ -10,8 +10,8 @@ spec = do describe "Undirected Graph (UGraph)" $ do it "Can tell if a vertex exists" $ property $ do- let g = insertVertex 1 empty :: UGraph Int ()- let g' = insertVertex 2 empty :: UGraph Int ()+ let g = insertVertex empty 1 :: UGraph Int ()+ let g' = insertVertex empty 2 :: UGraph Int () containsVertex g 1 `shouldBe` True containsVertex g' 1 `shouldBe` False @@ -27,12 +27,12 @@ it "Increments its order when a new vertex is inserted" $ property $ \g v -> (not $ g `containsVertex` v)- ==> order g + 1 == order (insertVertex v (g :: UGraph Int ()))+ ==> order g + 1 == order (insertVertex (g :: UGraph Int ()) v) it "Increments its size when a new edge is inserted" $ property $ \g edge -> (not $ g `containsEdge` edge) ==> size g + 1 == size (insertEdge edge (g :: UGraph Int ())) it "Is id when inserting and removing a new vertex" $ property $ \g v -> (not $ g `containsVertex` v)- ==> ((removeVertex v . insertVertex v) g)+ ==> (removeVertex v $ insertVertex g v) == (g :: UGraph Int ())