packages feed

graphite 0.4.2.0 → 0.5.0.0

raw patch · 14 files changed

+334/−141 lines, 14 filesdep +criteriondep +deepseqdep +dequeuedep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: criterion, deepseq, dequeue

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.Graph.DGraph: removeArcAndVertices' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e
- Data.Graph.DGraph: removeVertex :: (Hashable v, Eq v) => v -> DGraph v e -> DGraph v e
- Data.Graph.DGraph: type DegreeSequence = [(Int, Int)]
- Data.Graph.Generation: P :: Double -> Probability
- Data.Graph.Generation: instance GHC.Classes.Eq Data.Graph.Generation.Probability
- Data.Graph.Generation: instance GHC.Classes.Ord Data.Graph.Generation.Probability
- Data.Graph.Generation: instance GHC.Show.Show Data.Graph.Generation.Probability
- Data.Graph.Generation: newtype Probability
- Data.Graph.Generation: probability :: Double -> Probability
- Data.Graph.Read: csvToUGraph :: (Hashable v, Eq v, FromField v) => FilePath -> IO (Either String (UGraph v ()))
- Data.Graph.UGraph: removeEdgeAndVertices' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e
- Data.Graph.UGraph: removeVertex :: (Hashable v, Eq v) => v -> UGraph v e -> UGraph v e
+ Data.Graph.DGraph: instance (Control.DeepSeq.NFData v, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Data.Graph.DGraph.DGraph v e)
+ Data.Graph.DGraph: instance GHC.Generics.Generic (Data.Graph.DGraph.DGraph v e)
+ Data.Graph.DGraph.DegreeSequence: DegreeSequence :: [(Int, Int)] -> DegreeSequence
+ Data.Graph.DGraph.DegreeSequence: [unDegreeSequence] :: DegreeSequence -> [(Int, Int)]
+ Data.Graph.DGraph.DegreeSequence: instance GHC.Classes.Eq Data.Graph.DGraph.DegreeSequence.DegreeSequence
+ Data.Graph.DGraph.DegreeSequence: instance GHC.Classes.Ord Data.Graph.DGraph.DegreeSequence.DegreeSequence
+ Data.Graph.DGraph.DegreeSequence: instance GHC.Show.Show Data.Graph.DGraph.DegreeSequence.DegreeSequence
+ Data.Graph.DGraph.DegreeSequence: newtype DegreeSequence
+ Data.Graph.Generation: erdosRenyiD :: Int -> Float -> IO (DGraph Int ())
+ Data.Graph.Generation: erdosRenyiU :: Int -> Float -> IO (UGraph Int ())
+ Data.Graph.Read: fromCsv :: Graph g => (Hashable v, Eq v, FromField v) => FilePath -> IO (Either String (g v ()))
+ Data.Graph.Read: fromCsv' :: Graph g => (Hashable v, Eq v, FromField v) => FilePath -> IO (g v ())
+ Data.Graph.Types: insertEdgePairs :: (Graph g, Hashable v, Eq v) => [(v, v)] -> g v () -> g v ()
+ Data.Graph.Types: instance (Control.DeepSeq.NFData v, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Data.Graph.Types.Arc v e)
+ Data.Graph.Types: instance (Control.DeepSeq.NFData v, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Data.Graph.Types.Edge v e)
+ Data.Graph.Types: instance GHC.Generics.Generic (Data.Graph.Types.Arc v e)
+ Data.Graph.Types: instance GHC.Generics.Generic (Data.Graph.Types.Edge v e)
+ Data.Graph.Types: linksToEdges' :: (Eq v) => (v, Links v a) -> [Edge v a]
+ Data.Graph.Types: removeEdgePairs :: (Graph g, Hashable v, Eq v) => [(v, v)] -> g v e -> g v e
+ Data.Graph.Types: removeVertex :: (Graph g, Hashable v, Eq v) => v -> g v e -> g v e
+ Data.Graph.Types: removeVertices :: (Graph g, Hashable v, Eq v) => [v] -> g v e -> g v e
+ Data.Graph.UGraph: instance (Control.DeepSeq.NFData v, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Data.Graph.UGraph.UGraph v e)
+ Data.Graph.UGraph: instance GHC.Generics.Generic (Data.Graph.UGraph.UGraph v e)
- Data.Graph.DGraph: insertArc :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e
+ Data.Graph.DGraph: insertArc :: (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) => Arc v e -> 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: removeArc' :: (Hashable v, Eq v) => (v, v) -> 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) => Arc v e -> DGraph v e -> DGraph v e
- Data.Graph.Generation: erdosRenyi :: Graph g => Int -> Probability -> IO (g Int ())
+ Data.Graph.Generation: erdosRenyi :: Graph g => Int -> Float -> IO (g Int ())
- Data.Graph.Types: class Graph g where size = length . edgePairs degrees g = vertexDegree g <$> vertices g maxDegree = maximum . degrees minDegree = minimum . degrees avgDegree g = fromIntegral (2 * size g) / (fromIntegral $ order g) density g = (2 * (e - n + 1)) / (n * (n - 3) + 2) where n = fromIntegral $ order g e = fromIntegral $ size g
+ Data.Graph.Types: class Graph g where size = length . edgePairs degrees g = vertexDegree g <$> vertices g maxDegree = maximum . degrees minDegree = minimum . degrees avgDegree g = fromIntegral (2 * size g) / (fromIntegral $ order g) density g = (2 * (e - n + 1)) / (n * (n - 3) + 2) where n = fromIntegral $ order g e = fromIntegral $ size g insertVertices vs g = foldl' (flip insertVertex) g vs insertEdgePairs es g = foldl' (flip insertEdgePair) g es removeVertices vs g = foldl' (flip removeVertex) g vs removeEdgePairs es g = foldl' (flip removeEdgePair) g es removeEdgePairAndVertices (v1, v2) g = removeVertex v2 $ removeVertex v1 $ removeEdgePair (v1, v2) g
- Data.Graph.Types: insertEdgePair :: (Graph g, Hashable v, Eq v) => g v () -> (v, v) -> g v ()
+ Data.Graph.Types: insertEdgePair :: (Graph g, Hashable v, Eq v) => (v, v) -> g v () -> g v ()
- Data.Graph.Types: insertVertex :: (Graph g, Hashable v, Eq v) => g v e -> v -> g v e
+ Data.Graph.Types: insertVertex :: (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: insertVertices :: (Graph g, Hashable v, Eq v) => [v] -> g v e -> g v e
- Data.Graph.Types: linksToEdges :: (Eq v) => [(v, Links v a)] -> [Edge v a]
+ Data.Graph.Types: linksToEdges :: [(v, Links v a)] -> [Edge v a]
- Data.Graph.Types: removeEdgePair :: (Graph g, Hashable v, Eq v) => g v e -> (v, 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: removeEdgePairAndVertices :: (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.UGraph: insertEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e
+ Data.Graph.UGraph: insertEdge :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e
- Data.Graph.UGraph: insertEdges :: (Hashable v, Eq v) => UGraph v e -> [Edge v e] -> UGraph v e
+ Data.Graph.UGraph: insertEdges :: (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) => Edge v e -> 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: removeEdge' :: (Hashable v, Eq v) => (v, v) -> 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) => Edge v e -> UGraph v e -> UGraph v e

Files

README.md view
@@ -2,6 +2,7 @@  [![](https://img.shields.io/hackage/v/graphite.svg)](https://hackage.haskell.org/package/graphite) ![Hackage-Deps](https://img.shields.io/hackage-deps/v/graphite.svg)+[![CircleCI](https://circleci.com/gh/alx741/graphite.svg?style=svg)](https://circleci.com/gh/alx741/graphite)  # graphite 
+ benchmark/Main.hs view
@@ -0,0 +1,45 @@+module Main where++import Criterion.Main++import Control.DeepSeq+import Data.Graph.Generation++import Data.Graph.DGraph+import Data.Graph.Types+import Data.Graph.UGraph++main = do+    ug100 <- force <$> erdosRenyi 100 0.3 :: IO (UGraph Int ())+    ug500 <- force <$> erdosRenyi 500 0.3 :: IO (UGraph Int ())+    ug1000 <- force <$> erdosRenyi 1000 0.3 :: IO (UGraph Int ())++    dg100 <- force <$> erdosRenyi 100 0.3 :: IO (DGraph Int ())+    dg500 <- force <$> erdosRenyi 500 0.3 :: IO (DGraph Int ())+    dg1000 <- force <$> erdosRenyi 1000 0.3 :: IO (DGraph Int ())++    defaultMain+        [ bgroup "generation"+            [ bench "gnp_100" $ nfIO (erdosRenyi 100 0.3 :: IO (UGraph Int ()))+            , bench "gnp_500" $ nfIO (erdosRenyi 500 0.3 :: IO (UGraph Int ()))+            , bench "gnp_1000" $ nfIO (erdosRenyi 1000 0.3 :: IO (UGraph Int ()))+            , bench "gnp_5000" $ nfIO (erdosRenyi 2000 0.3 :: IO (UGraph Int ()))+            ]++        , bgroup "edges"+            [ bench "edges_ug100" $ nf edges ug100+            , bench "edges_ug500" $ nf edges ug500+            , bench "edges_ug1000" $ nf edges ug1000++            , bench "arcs_dg100" $ nf arcs dg100+            , bench "arcs_dg500" $ nf arcs dg500+            , bench "arcs_dg1000" $ nf arcs dg1000+            ]++        , bgroup "properties"+            [ bench "order_ug100" $ whnf order ug100+            , bench "size_ug100" $ whnf size ug100+            , bench "order_ug500" $ whnf order ug500+            , bench "size_ug500" $ whnf size ug500+            ]+        ]
graphite.cabal view
@@ -1,5 +1,5 @@ name:                graphite-version:             0.4.2.0+version:             0.5.0.0 synopsis:            Graphs and networks library description:         Represent, analyze and visualize graphs homepage:            https://github.com/alx741/graphite#readme@@ -22,19 +22,23 @@                      , Data.Graph.Morphisms                      , Data.Graph.Read                      , Data.Graph.UGraph+                     , Data.Graph.DGraph.DegreeSequence                      , Data.Graph.UGraph.DegreeSequence                      , Data.Graph.Visualize+  other-modules:       Scratch   build-depends:       base >= 4.7 && < 5-                     , hashable-                     , vector-                     , containers-                     , unordered-containers-                     , bytestring-                     , random-                     , process-                     , graphviz                      , QuickCheck+                     , bytestring                      , cassava+                     , containers+                     , deepseq+                     , dequeue+                     , graphviz+                     , hashable+                     , process+                     , random+                     , unordered-containers+                     , vector   ghc-options:         -Wall   default-language:    Haskell2010 @@ -50,6 +54,17 @@                      , Data.Graph.DGraphSpec                      , Data.Graph.UGraphSpec   ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++benchmark graphite-benchmark+  type:                exitcode-stdio-1.0+  hs-source-dirs:      benchmark+  main-is:             Main.hs+  build-depends:       base+                     , graphite+                     , deepseq+                     , criterion+  ghc-options:         -O2   default-language:    Haskell2010  source-repository head
src/Data/Graph/Connectivity.hs view
@@ -66,7 +66,7 @@ isBridgeless :: (Hashable v, Eq v, Ord v) => UGraph v e -> Bool -- FIXME: Use a O(n) algorithm isBridgeless g =-    foldl' (\b vs -> b && isConnected (removeEdgePair g vs)) True (edgePairs g)+    foldl' (\b vs -> b && isConnected (removeEdgePair vs g)) True (edgePairs g)  -- | Tell if a 'UGraph' is orietable -- | An undirected graph is @orietable@ if it can be converted into a directed
src/Data/Graph/DGraph.hs view
@@ -1,10 +1,13 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE DeriveGeneric       #-} {-# LANGUAGE ScopedTypeVariables #-}  module Data.Graph.DGraph where -import Data.List (foldl')+import Data.List    (foldl')+import GHC.Generics (Generic) +import           Control.DeepSeq import           Data.Hashable import qualified Data.HashMap.Lazy as HM import           Test.QuickCheck@@ -15,7 +18,7 @@  -- | Directed Graph of Vertices in /v/ and Arcs with attributes in /e/ newtype DGraph v e = DGraph { unDGraph :: HM.HashMap v (Links v e) }-    deriving (Eq)+    deriving (Eq, Generic)  instance (Hashable v, Eq v, Show v, Show e) => Show (DGraph v e) where     showsPrec d m = showParen (d > 10) $@@ -27,6 +30,8 @@         xs <- readPrec         return (fromList xs) +instance (NFData v, NFData e) => NFData (DGraph v e)+ instance Graph DGraph where     empty = DGraph HM.empty     order (DGraph g) = HM.size g@@ -44,15 +49,17 @@     -- | The total number of inbounding and outbounding 'Arc's of a vertex     vertexDegree g v = vertexIndegree g v + vertexOutdegree g v -    insertVertex (DGraph g) v = DGraph $ hashMapInsert v HM.empty g-    insertVertices = foldl' insertVertex+    insertVertex v (DGraph g) = DGraph $ hashMapInsert v HM.empty g      containsEdgePair = containsArc'     incidentEdgePairs g v = fmap toPair $ incidentArcs g v-    insertEdgePair g (v1, v2) = insertArc g (Arc v1 v2 ())+    insertEdgePair (v1, v2) g = insertArc (Arc v1 v2 ()) g     removeEdgePair = removeArc'-    removeEdgePairAndVertices = removeArcAndVertices' +    removeVertex v g = DGraph+        $ (\(DGraph g') -> HM.delete v g')+        $ foldl' (flip removeArc) g $ incidentArcs g v+     isSimple g = foldl' go True $ vertices g         where go bool v = bool && (not $ HM.member v $ getLinks v $ unDGraph g) @@ -69,54 +76,39 @@      toAdjacencyMatrix = undefined --- | The Degree Sequence of a 'DGraph' is a list of pairs (Indegree, Outdegree)-type DegreeSequence = [(Int, Int)]- instance (Arbitrary v, Arbitrary e, Hashable v, Num v, Ord v)  => Arbitrary (DGraph v e) where     arbitrary = insertArcs <$> pure empty <*> arbitrary --- | @O(n)@ Remove a vertex from a 'DGraph' if present--- | Every 'Arc' incident to this vertex is also removed-removeVertex :: (Hashable v, Eq v) => v -> DGraph v e -> DGraph v e-removeVertex v g = DGraph-    $ (\(DGraph g') -> HM.delete v g')-    $ 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 -- | contains the Arc, its attribute is updated-insertArc :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e-insertArc g (Arc fromV toV edgeAttr) = DGraph+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 g [fromV, toV]+    where g' = unDGraph $ insertVertices [fromV, toV] g  -- | @O(m*log n)@ Insert many directed 'Arc's into a 'DGraph' -- | Same rules as 'insertArc' are applied insertArcs :: (Hashable v, Eq v) => DGraph v e -> [Arc v e] -> DGraph v e-insertArcs g as = foldl' insertArc g as+insertArcs g as = foldl' (flip insertArc) g as  -- | @O(log n)@ Remove the directed 'Arc' from a 'DGraph' if present -- | The involved vertices are left untouched-removeArc :: (Hashable v, Eq v) => DGraph v e -> Arc v e -> DGraph v e-removeArc g = removeEdgePair g . toPair+removeArc :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e+removeArc = removeEdgePair . toPair  -- | Same as 'removeArc' but the arc is an ordered pair-removeArc' :: (Hashable v, Eq v) => DGraph v e -> (v, v) -> DGraph v e-removeArc' (DGraph g) (v1, v2) = case HM.lookup v1 g of+removeArc' :: (Hashable v, Eq v) => (v, v) -> DGraph v e -> DGraph v e+removeArc' (v1, v2) (DGraph g) = 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) => 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) => DGraph v e -> (v, v) -> DGraph v e-removeArcAndVertices' g (v1, v2) =-    removeVertex v2 $ removeVertex v1 $ removeEdgePair g (v1, v2)+removeArcAndVertices :: (Hashable v, Eq v) => Arc v e -> DGraph v e -> DGraph v e+removeArcAndVertices = removeEdgePairAndVertices . toPair  -- | @O(n*m)@ Retrieve the 'Arc's of a 'DGraph' arcs :: forall v e . (Hashable v, Eq v) => DGraph v e -> [Arc v e]@@ -192,7 +184,7 @@ -- | Tell if a 'DGraph' is regular -- | A Directed Graph is @regular@ when all of its vertices have the same number -- | of adjacent vertices AND when the @indegree@ and @outdegree@ of each vertex--- | are equal to each toher.+-- | are equal to each other. isRegular :: DGraph v e -> Bool isRegular _ = undefined @@ -223,7 +215,7 @@ -- | 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 empty (fmap arcToEdge $ arcs g)+toUndirected g = UG.insertEdges (fmap arcToEdge $ arcs g) empty     where arcToEdge (Arc fromV toV attr) = Edge fromV toV attr  
+ src/Data/Graph/DGraph/DegreeSequence.hs view
@@ -0,0 +1,5 @@+module Data.Graph.DGraph.DegreeSequence where++-- | The Degree Sequence of a 'DGraph' is a list of pairs (Indegree, Outdegree)+newtype DegreeSequence = DegreeSequence { unDegreeSequence :: [(Int, Int)] }+    deriving (Eq, Ord, Show)
src/Data/Graph/Generation.hs view
@@ -6,33 +6,40 @@ import Data.List     (foldl') import System.Random +import Data.Graph.DGraph import Data.Graph.Types---- | Probability value between 0 and 1-newtype Probability = P Double deriving (Eq, Ord, Show)---- | Construct a 'Probability' value-probability :: Double -> Probability-probability v | v >= 1 = P 1 | v <= 0 = P 0 | otherwise = P v+import Data.Graph.UGraph --- | Generate a random Erdős–Rényi  G(n, p) model graph-erdosRenyi :: Graph g => Int -> Probability -> IO (g Int ())-erdosRenyi n (P p) = go [1..n] p empty+-- | Generate a random Erdős–Rényi G(n, p) model graph of /n/ vertices with a+-- | /p/ connection probability+erdosRenyi :: Graph g => Int -> Float -> IO (g Int ())+erdosRenyi n p = go [1..n] (probability p) empty     where-        go :: Graph g => [Int] -> Double -> g Int () -> IO (g Int ())+        go :: Graph g => [Int] -> Float -> g Int () -> IO (g Int ())         go [] _ g = return g         go (v:vs) pv g = do             rnds <- replicateM (length vs + 1) $ randomRIO (0.0, 1.0)             flipDir <- randomRIO (True, False)             let vs' = zip rnds vs-            let g' = insertVertex g v+            let g' = insertVertex v g             go vs pv $! (foldl' (putV pv v flipDir) g' vs') -        putV :: Graph g => Double -> Int -> Bool -> g Int () -> (Double, Int) -> g Int ()+        putV :: Graph g => Float -> Int -> Bool -> g Int () -> (Float, Int) -> g Int ()         putV pv v flipDir g (p', v')-            | p' < pv = insertEdgePair g pair+            | p' < pv = insertEdgePair pair g             | otherwise = g                 where pair = if flipDir then (v', v) else (v, v')++        probability :: Float -> Float+        probability v | v >= 1 = 1 | v <= 0 = 0 | otherwise = v++-- | 'erdosRenyi' convinience 'UGraph' generation function+erdosRenyiU :: Int -> Float -> IO (UGraph Int ())+erdosRenyiU  = erdosRenyi++-- | 'erdosRenyi' convinience 'DGraph' generation function+erdosRenyiD :: Int -> Float -> IO (DGraph Int ())+erdosRenyiD  = erdosRenyi  -- | Generate a random square binary matrix -- | Useful for use with 'fromAdjacencyMatrix'
src/Data/Graph/Read.hs view
@@ -2,31 +2,41 @@  module Data.Graph.Read where -import Data.ByteString.Lazy as BS+import Data.ByteString.Lazy as BS hiding (empty) import Data.Csv             as CSV import Data.Hashable-import Data.Vector          as V hiding (fromList)+import Data.Vector          as V hiding (empty, fromList)  import Data.Graph.Types-import Data.Graph.UGraph  -- | Read a 'UGraph' from a CSV file -- | The line "1,2,3,4" translates to the list of edges -- | "(1 <-> 2), (1 <-> 3), (1 <-> 4)"-csvToUGraph :: (Hashable v, Eq v, FromField v)-    => FilePath-    -> IO (Either String (UGraph v ()))-csvToUGraph fp = do+fromCsv :: Graph g => (Hashable v, Eq v, FromField v)+ => FilePath+ -> IO (Either String (g v ()))+fromCsv fp = do     content <- BS.readFile fp     let dec = decode NoHeader content     case dec of-        Left err  -> return $ Left err-        Right vec -> return $ Right $ fromList $ toEdges $ V.toList vec+        Left err -> return $ Left err+        Right vec -> return $ Right $ (flip insertEdgePairs) empty $ toEdges $ V.toList vec      where-        toEdges :: [[v]] -> [Edge v ()]+        toEdges :: [[v]] -> [(v, v)]         toEdges ns = Prelude.concat $ fmap nodeEdges ns -        nodeEdges :: [v] -> [Edge v ()]+        nodeEdges :: [v] -> [(v, v)]         nodeEdges []     = []-        nodeEdges (n:ns) = fmap (\n' -> Edge n n' ()) ns+        nodeEdges (n:ns) = fmap (\n' -> (n, n')) ns+++-- | Same as 'fromCsv' but rise an exception when parsing fails+fromCsv' :: Graph g => (Hashable v, Eq v, FromField v)+ => FilePath+ -> IO (g v ())+fromCsv' fp = do+    eitherG <- fromCsv fp+    case eitherG of+        Left err -> error err+        Right g -> return g
src/Data/Graph/Types.hs view
@@ -1,11 +1,14 @@+{-# LANGUAGE DeriveGeneric       #-} {-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE ScopedTypeVariables #-}  module Data.Graph.Types where -import Data.List (nubBy)-import GHC.Float (float2Double)+import Data.List    (foldl')+import GHC.Float    (float2Double)+import GHC.Generics (Generic) +import           Control.DeepSeq import           Data.Hashable import qualified Data.HashMap.Lazy as HM import           Test.QuickCheck@@ -75,12 +78,13 @@      -- | Insert a vertex into a graph     -- | If the graph already contains the vertex leave the graph untouched-    insertVertex :: (Hashable v, Eq v) => g v e -> v -> g v e+    insertVertex :: (Hashable v, Eq v) => v -> g v e -> 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) => g v e -> [v] -> g v e+    insertVertices :: (Hashable v, Eq v) => [v] -> g v e -> g v e+    insertVertices vs g = foldl' (flip insertVertex) g vs      -- | Tell if an edge exists in the graph     containsEdgePair :: (Hashable v, Eq v) => g v e -> (v, v) -> Bool@@ -91,15 +95,33 @@     -- | 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) => g v () -> (v, v) -> g v ()+    insertEdgePair :: (Hashable v, Eq v) => (v, v) -> g v () -> g v () -    -- | Remove the edge from a graph present+    -- | Same as 'insertEdgePair' but for multiple edges+    insertEdgePairs :: (Hashable v, Eq v) => [(v, v)] -> g v () -> g v ()+    insertEdgePairs es g = foldl' (flip insertEdgePair) g es++    -- | Remove a vertex from a graph if present+    -- | Every edge incident to this vertex is also removed+    removeVertex :: (Hashable v, Eq v) => v -> g v e -> g v e++    -- | Same as 'removeVertex' but for multiple vertices+    removeVertices :: (Hashable v, Eq v) => [v] -> g v e -> g v e+    removeVertices vs g = foldl' (flip removeVertex) g vs++    -- | Remove an edge from a graph if present     -- | The involved vertices are left untouched-    removeEdgePair :: (Hashable v, Eq v) => g v e -> (v, v) -> g v e+    removeEdgePair :: (Hashable v, Eq v) => (v, v) -> g v e -> g v e +    -- | Same as 'removeEdgePair' but for multple edges+    removeEdgePairs :: (Hashable v, Eq v) => [(v, v)] -> g v e -> g v e+    removeEdgePairs es g = foldl' (flip removeEdgePair) g es+     -- | Remove the edge from a graph if present     -- | The involved vertices are also removed-    removeEdgePairAndVertices :: (Hashable v, Eq v) => g v e -> (v, v) -> g v e+    removeEdgePairAndVertices :: (Hashable v, Eq v) => (v, v) -> g v e -> g v e+    removeEdgePairAndVertices (v1, v2) g =+        removeVertex v2 $ removeVertex v1 $ removeEdgePair (v1, v2) g      -- | Tell if a graph is simple     -- | A graph is @simple@ if it has no loops@@ -114,11 +136,11 @@  -- | Undirected Edge with attribute of type /e/ between to Vertices of type /v/ data Edge v e = Edge v v e-    deriving (Show, Read, Ord)+    deriving (Show, Read, Ord, Generic)  -- | Directed Arc with attribute of type /e/ between to Vertices of type /v/ data Arc v e = Arc v v e-    deriving (Show, Read, Ord)+    deriving (Show, Read, Ord, Generic)  -- | Construct an undirected 'Edge' between two vertices (<->) :: (Hashable v) => v -> v -> Edge v ()@@ -136,6 +158,9 @@     -- | An edge forms a @loop@ if both of its ends point to the same vertex     isLoop :: (Eq v) => e v a -> Bool +instance (NFData v, NFData e) => NFData (Edge v e)+instance (NFData v, NFData e) => NFData (Arc v e)+ instance IsEdge Edge where     toPair (Edge v1 v2 _) = (v1, v2)     isLoop (Edge v1 v2 _) = v1 == v2@@ -193,8 +218,7 @@  -- | Edges generator arbitraryEdge :: (Arbitrary v, Arbitrary e, Ord v, Num v)- => (v -> v -> e -> edge)- -> Gen edge+ => (v -> v -> e -> edge) -> Gen edge arbitraryEdge edgeType = edgeType <$> vert <*> vert <*> arbitrary     where vert = getPositive <$> arbitrary @@ -227,14 +251,15 @@         toArc (fromV, links) = fmap (\(v, a) -> Arc fromV v a) (HM.toList links)  -- | Get 'Edge's from an association list of vertices and their links-linksToEdges :: (Eq v) => [(v, Links v a)] -> [Edge v a]-linksToEdges ls = nubBy shallowEdgeEq $ concat $ fmap toEdge ls+linksToEdges :: [(v, Links v a)] -> [Edge v a]+linksToEdges ls = concat $ fmap toEdge ls     where         toEdge :: (v, Links v a) -> [Edge v a]         toEdge (fromV, links) = fmap (\(v, a) -> Edge fromV v a) (HM.toList links)-        shallowEdgeEq (Edge v1 v2 _) (Edge v1' v2' _) =-               (v1 == v1' && v2 == v2')-            || (v1 == v2' && v2 == v1')++-- | Get 'Edge's from an association list of vertices and their links+linksToEdges' :: (Eq v) => (v, Links v a) -> [Edge v a]+linksToEdges' (fromV, links) = fmap (\(v, a) -> Edge fromV v a) (HM.toList links)  -- | O(log n) Associate the specified value with the specified key in this map. -- | If this map previously contained a mapping for the key, leave the map
src/Data/Graph/UGraph.hs view
@@ -1,13 +1,18 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE DeriveGeneric       #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns        #-}  module Data.Graph.UGraph where -import Data.List (foldl')+import qualified Data.Foldable as F (toList)+import           Data.List     (foldl')+import           GHC.Generics  (Generic) +import           Control.DeepSeq import           Data.Hashable import qualified Data.HashMap.Lazy as HM+import qualified Data.Sequence     as S import           Test.QuickCheck import           Text.Read @@ -15,7 +20,7 @@  -- | Undirected Graph of Vertices in /v/ and Edges with attributes in /e/ newtype UGraph v e = UGraph { unUGraph :: HM.HashMap v (Links v e) }-    deriving (Eq)+    deriving (Eq, Generic)  instance (Hashable v, Eq v, Show v, Show e) => Show (UGraph v e) where     showsPrec d m = showParen (d > 10) $@@ -27,9 +32,11 @@         xs <- readPrec         return (fromList xs) +instance (NFData v, NFData e) => NFData (UGraph v e)+ instance (Arbitrary v, Arbitrary e, Hashable v, Num v, Ord v)  => Arbitrary (UGraph v e) where-    arbitrary = insertEdges <$> pure empty <*> arbitrary+    arbitrary = insertEdges <$> arbitrary <*> pure empty  instance Graph UGraph where     empty = UGraph HM.empty@@ -42,21 +49,23 @@     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 (UGraph g) v = UGraph $ hashMapInsert v HM.empty g-    insertVertices = foldl' insertVertex+    insertVertex v (UGraph g) = UGraph $ hashMapInsert v HM.empty g      containsEdgePair = containsEdge'     incidentEdgePairs g v = fmap toPair $ incidentEdges g v-    insertEdgePair g (v1, v2) = insertEdge g (Edge v1 v2 ())+    insertEdgePair (v1, v2) g = insertEdge (Edge v1 v2 ()) g     removeEdgePair = removeEdge'-    removeEdgePairAndVertices = removeEdgeAndVertices' +    removeVertex v g = UGraph+        $ (\(UGraph g') -> HM.delete v g')+        $ foldl' (flip removeEdge) g $ incidentEdges g v+     isSimple g = foldl' go True $ vertices g         where go bool v = bool && (not $ HM.member v $ getLinks v $ unUGraph g)      fromAdjacencyMatrix m         | length m /= length (head m) = Nothing-        | otherwise = Just $ insertEdges empty (foldl' genEdges [] labeledM)+        | otherwise = Just $ insertEdges (foldl' genEdges [] labeledM) empty             where                 labeledM :: [(Int, [(Int, Int)])]                 labeledM = zip [1..] $ fmap (zip [1..]) m@@ -69,38 +78,31 @@   --- | @O(n)@ Remove a vertex from a 'UGraph' if present--- | Every 'Edge' incident to this vertex is also removed-removeVertex :: (Hashable v, Eq v) => v -> UGraph v e -> UGraph v e-removeVertex v g = UGraph-    $ (\(UGraph g') -> HM.delete v g')-    $ 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 -- | contains the Edge, its attribute is updated-insertEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e-insertEdge g (Edge v1 v2 edgeAttr) = UGraph $ link v2 v1 $ link v1 v2 g'+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 g [v1, v2]+        g' = unUGraph $ insertVertices [v1, v2] g         link fromV toV = HM.adjust (insertLink toV edgeAttr) fromV  -- | @O(m*log n)@ Insert many directed 'Edge's into a 'UGraph' -- | Same rules as 'insertEdge' are applied-insertEdges :: (Hashable v, Eq v) => UGraph v e -> [Edge v e] -> UGraph v e-insertEdges = foldl' insertEdge+insertEdges :: (Hashable v, Eq v) => [Edge v e] -> UGraph v e -> UGraph v e+insertEdges es g = foldl' (flip insertEdge) g es  -- | @O(log n)@ Remove the undirected 'Edge' from a 'UGraph' if present -- | The involved vertices are left untouched-removeEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> UGraph v e-removeEdge g = removeEdgePair g . toPair+removeEdge :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e+removeEdge = removeEdgePair . toPair  -- | Same as 'removeEdge' but the edge is an unordered pair-removeEdge' :: (Hashable v, Eq v) => UGraph v e -> (v, v) -> UGraph v e-removeEdge' graph@(UGraph g) (v1, v2)+removeEdge' :: (Hashable v, Eq v) => (v, v) -> UGraph v e -> UGraph v e+removeEdge' (v1, v2) graph@(UGraph g)     | containsVertex graph v1 && containsVertex graph v2 =         UGraph $ update v2Links v2 $ update v1Links v1 g-    | otherwise = UGraph g+    | otherwise = graph     where         v1Links = HM.delete v2 $ getLinks v1 g         v2Links = HM.delete v1 $ getLinks v2 g@@ -108,22 +110,19 @@  -- | @O(log n)@ Remove the undirected 'Edge' from a 'UGraph' if present -- | The involved vertices are also removed-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) => UGraph v e -> (v, v) -> UGraph v e-removeEdgeAndVertices' g (v1, v2) =-    removeVertex v2 $ removeVertex v1 $ removeEdgePair g (v1, v2)+removeEdgeAndVertices :: (Hashable v, Eq v) => Edge v e -> UGraph v e -> UGraph v e+removeEdgeAndVertices = removeEdgePairAndVertices . toPair  -- | @O(n*m)@ Retrieve the 'Edge's of a 'UGraph' edges :: forall v e . (Hashable v, Eq v) => UGraph v e -> [Edge v e]-edges (UGraph g) = linksToEdges $ zip vs links+edges g = F.toList $ go g S.empty     where-        vs :: [v]-        vs = vertices $ UGraph g-        links :: [Links v e]-        links = fmap (`getLinks` g) vs+        go (order -> 0) es = es+        go g' es =+            let v = head $ vertices g'+            in go+                (removeVertex v g')+                (es S.>< (S.fromList $ incidentEdges g' v))  -- | @O(log n)@ Tell if an undirected 'Edge' exists in the graph containsEdge :: (Hashable v, Eq v) => UGraph v e -> Edge v e -> Bool@@ -149,4 +148,4 @@  -- | Construct a 'UGraph' from a list of 'Edge's fromList :: (Hashable v, Eq v) => [Edge v e] -> UGraph v e-fromList = insertEdges empty+fromList es = insertEdges es empty
src/Data/Graph/Visualize.hs view
@@ -7,6 +7,7 @@     ) where  import Data.GraphViz+import Data.GraphViz.Attributes.Complete import Data.Hashable  import Data.Graph.DGraph@@ -40,8 +41,14 @@  toUndirectedDot :: (Show e) => UGraph Int e -> DotGraph Int toUndirectedDot g = graphElemsToDot params (labeledNodes g) (labeledEdges g)-    where params = nonClusteredParams { isDirected = False }+    where params = nonClusteredParams+            { isDirected = False+            , globalAttributes = [GraphAttrs [Overlap ScaleOverlaps]]+            }  toDirectedDot :: (Show e) => DGraph Int e -> DotGraph Int toDirectedDot g = graphElemsToDot params (labeledNodes g) (labeledArcs g)-    where params = nonClusteredParams { isDirected = True }+    where params = nonClusteredParams+            { isDirected = True+            , globalAttributes = [GraphAttrs [Overlap ScaleOverlaps]]+            }
+ src/Scratch.hs view
@@ -0,0 +1,73 @@+module Scratch where++import Data.List (foldl')++import qualified Data.Dequeue as Q+import qualified Data.Set     as S++import Data.Graph.Types+import Data.Graph.UGraph++testG :: UGraph Int ()+testG = fromList+    [ 1 <-> 2+    , 1 <-> 3+    , 1 <-> 5+    , 2 <-> 1+    , 2 <-> 4+    , 3 <-> 4+    , 3 <-> 6+    , 4 <-> 2+    , 4 <-> 3+    , 4 <-> 5+    , 5 <-> 1+    , 5 <-> 4+    , 5 <-> 6+    , 6 <-> 5+    , 6 <-> 3+    ]++path :: UGraph Int () -> Int -> Int -> [Int]+path g fromV toV+    | fromV == toV = [toV]+    | otherwise = search [fromV] S.empty []+    where+        search :: [Int] -> S.Set Int -> [Int] -> [Int]+        search (v:vs) banned popped+            | v == toV = popped ++ [v]+            | otherwise =+                let reachables = nonVisitedReachables banned v+                in search+                    (vs ++ reachables)+                    (setInsertMany banned $ v : reachables)+                    (popped ++ [v])++        nonVisitedReachables banned v = filter+            (\v' -> v' /= v && (not $ S.member v' banned))+            (directlyReachableVertices g v)++path' :: UGraph Int () -> Int -> Int -> [Int]+path' g fromV toV+    | fromV == toV = [toV]+    | otherwise = reverse $ search (Q.fromList [fromV]) S.empty []+    where+        search :: Q.BankersDequeue Int -> S.Set Int -> [Int] -> [Int]+        search queue banned popped = case Q.popFront queue of+            Nothing -> popped+            Just (v, queue') -> if v == toV then v : popped else+                let reachables = nonVisitedReachables banned v+                in search+                    (queue' `pushBackMany` reachables)+                    (setInsertMany banned $ v : reachables)+                    (v : popped)++        nonVisitedReachables banned v = filter+            (\v' -> v' /= v && (not $ S.member v' banned))+            (directlyReachableVertices g v)+++setInsertMany :: Ord a => S.Set a -> [a] -> S.Set a+setInsertMany = foldl' (flip S.insert)++pushBackMany :: Q.BankersDequeue a  -> [a] -> Q.BankersDequeue a+pushBackMany = foldl' Q.pushBack
test/Data/Graph/DGraphSpec.hs view
@@ -10,25 +10,32 @@ spec = do     describe "Directed Graph (DGraph)" $ do         it "Can tell if a vertex exists" $ property $ do-            let g = insertVertex empty 1 :: DGraph Int ()-            let g' = insertVertex empty 2 :: DGraph Int ()+            let g = insertVertex 1 empty :: DGraph Int ()+            let g' = insertVertex 2 empty :: DGraph Int ()             containsVertex g 1 `shouldBe` True             containsVertex g' 1 `shouldBe` False          it "Can tell if an arc exists" $ property $ do-            let g = insertArc empty (1 --> 2) :: DGraph Int ()-            let g' = insertArc empty (2 --> 1) :: DGraph Int ()+            let g = insertArc (1 --> 2) empty :: DGraph Int ()+            let g' = insertArc (2 --> 1) empty :: DGraph Int ()             containsArc g (1 --> 2) `shouldBe` True             containsArc g' (1 --> 2) `shouldBe` False          it "Increments its order when a new vertex is inserted" $ property $             \g v -> (not $ g `containsVertex` v)-                ==> order g + 1 == order (insertVertex (g :: DGraph Int ()) v)+                ==> order g + 1 == order (insertVertex v (g :: DGraph Int ()))         it "Increments its size when a new arc is inserted" $ property $-            \g arc -> (not $ g `containsArc` arc)-                ==> size g + 1 == size (insertArc (g :: DGraph Int ()) arc)+            \g a -> (not $ g `containsArc` a)+                ==> size g + 1 == size (insertArc a (g :: DGraph Int ())) +        it "order is conserved" $ property $+            \g v -> (not $ g `containsVertex` v)+                ==> order g == order (removeVertex v $ insertVertex v (g :: DGraph Int ()))+        it "size is conserved" $ property $+            \g a -> (not $ g `containsArc` a)+                ==> size g == size (removeArc a $ insertArc a (g :: DGraph Int ()))+         it "Is id when inserting and removing a new vertex" $ property $             \g v -> (not $ g `containsVertex` v)-                ==> (removeVertex v $ insertVertex g v)+                ==> (removeVertex v $ insertVertex v g)                     == (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 empty 1 :: UGraph Int ()-            let g' = insertVertex empty 2 :: UGraph Int ()+            let g = insertVertex 1 empty :: UGraph Int ()+            let g' = insertVertex 2 empty :: UGraph Int ()             containsVertex g 1 `shouldBe` True             containsVertex g' 1 `shouldBe` False @@ -27,12 +27,19 @@          it "Increments its order when a new vertex is inserted" $ property $             \g v -> (not $ g `containsVertex` v)-                ==> order g + 1 == order (insertVertex (g :: UGraph Int ()) v)+                ==> order g + 1 == order (insertVertex v (g :: UGraph Int ()))         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 ()))+            \g e -> (not $ g `containsEdge` e)+                ==> size g + 1 == size (insertEdge e (g :: UGraph Int ())) +        it "order is conserved" $ property $+            \g v -> (not $ g `containsVertex` v)+                ==> order g == order (removeVertex v $ insertVertex v (g :: UGraph Int ()))+        it "size is conserved" $ property $+            \g e -> (not $ g `containsEdge` e)+                ==> size g == size (removeEdge e $ insertEdge e (g :: UGraph Int ()))+         it "Is id when inserting and removing a new vertex" $ property $             \g v -> (not $ g `containsVertex` v)-                ==> (removeVertex v $ insertVertex g v)+                ==> (removeVertex v $ insertVertex v g)                     == (g :: UGraph Int ())