2018-05-11 19:09:21 +03:00
|
|
|
|
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies, UndecidableInstances #-}
|
2018-05-11 19:07:05 +03:00
|
|
|
|
module Data.Graph
|
|
|
|
|
( Graph(..)
|
2018-05-11 19:09:37 +03:00
|
|
|
|
, Class.overlay
|
|
|
|
|
, Class.connect
|
|
|
|
|
, Class.vertex
|
2018-05-11 19:21:49 +03:00
|
|
|
|
, Lower(..)
|
2018-05-11 19:10:27 +03:00
|
|
|
|
, simplify
|
2018-06-18 16:34:21 +03:00
|
|
|
|
, topologicalSort
|
2018-06-20 19:28:09 +03:00
|
|
|
|
, EdgeCounts(..)
|
2018-05-11 19:07:05 +03:00
|
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
import qualified Algebra.Graph as G
|
2018-05-11 19:09:21 +03:00
|
|
|
|
import qualified Algebra.Graph.Class as Class
|
2018-05-11 19:22:11 +03:00
|
|
|
|
import Data.Aeson
|
2018-06-19 19:57:59 +03:00
|
|
|
|
import Data.List (groupBy, sortBy)
|
2018-06-18 16:34:21 +03:00
|
|
|
|
import qualified Data.List.NonEmpty as NonEmpty (fromList)
|
|
|
|
|
import qualified Data.Map.Monoidal as Monoidal
|
|
|
|
|
import Data.Ord (comparing)
|
2018-05-11 19:10:59 +03:00
|
|
|
|
import Prologue
|
2018-05-11 19:07:05 +03:00
|
|
|
|
|
2018-05-11 19:12:23 +03:00
|
|
|
|
-- | An algebraic graph with 'Ord', 'Semigroup', and 'Monoid' instances.
|
2018-05-11 19:07:05 +03:00
|
|
|
|
newtype Graph vertex = Graph (G.Graph vertex)
|
2018-06-20 19:40:33 +03:00
|
|
|
|
deriving (Alternative, Applicative, Eq, Foldable, Functor, Class.Graph, Monad, Show, Class.ToGraph, Traversable)
|
2018-05-11 19:10:27 +03:00
|
|
|
|
|
|
|
|
|
|
2018-05-11 19:12:05 +03:00
|
|
|
|
simplify :: Ord vertex => Graph vertex -> Graph vertex
|
2018-05-11 19:10:27 +03:00
|
|
|
|
simplify (Graph graph) = Graph (G.simplify graph)
|
2018-05-11 19:10:59 +03:00
|
|
|
|
|
|
|
|
|
|
2018-06-25 22:52:27 +03:00
|
|
|
|
-- | Sort a graph’s vertices topologically.
|
2018-06-25 20:02:37 +03:00
|
|
|
|
--
|
|
|
|
|
-- >>> topologicalSort (Class.path "ab")
|
|
|
|
|
-- ['b' :| "",'a' :| ""]
|
2018-06-25 20:02:49 +03:00
|
|
|
|
--
|
|
|
|
|
-- >>> topologicalSort (Class.path "abc")
|
|
|
|
|
-- ['c' :| "",'b' :| "",'a' :| ""]
|
2018-06-18 16:34:21 +03:00
|
|
|
|
topologicalSort :: Ord v => Graph v -> [NonEmpty v]
|
|
|
|
|
topologicalSort
|
2018-06-20 19:27:42 +03:00
|
|
|
|
= map (fmap fst)
|
2018-06-22 23:05:54 +03:00
|
|
|
|
. sortAndGroupBy (inEdgeCount . snd)
|
2018-06-19 19:57:59 +03:00
|
|
|
|
. Monoidal.pairs
|
2018-06-25 20:05:22 +03:00
|
|
|
|
. Class.foldg
|
|
|
|
|
lowerBound
|
|
|
|
|
(flip Monoidal.singleton mempty)
|
|
|
|
|
(<>)
|
|
|
|
|
(\ outM inM
|
|
|
|
|
-> outM
|
|
|
|
|
<> inM
|
|
|
|
|
<> foldMap (flip Monoidal.singleton (EdgeCounts 0 (length outM))) (Monoidal.keys inM)
|
|
|
|
|
<> foldMap (flip Monoidal.singleton (EdgeCounts (length inM) 0)) (Monoidal.keys outM))
|
2018-06-19 19:57:59 +03:00
|
|
|
|
|
2018-06-20 19:20:26 +03:00
|
|
|
|
data EdgeCounts = EdgeCounts
|
|
|
|
|
{ inEdgeCount :: {-# UNPACK #-} !Int
|
|
|
|
|
, outEdgeCount :: {-# UNPACK #-} !Int
|
|
|
|
|
}
|
|
|
|
|
deriving (Eq, Ord, Show)
|
|
|
|
|
|
2018-06-20 19:21:12 +03:00
|
|
|
|
instance Semigroup EdgeCounts where
|
|
|
|
|
EdgeCounts in1 out1 <> EdgeCounts in2 out2 = EdgeCounts (in1 + in2) (out1 + out2)
|
|
|
|
|
|
2018-06-20 19:21:48 +03:00
|
|
|
|
instance Monoid EdgeCounts where
|
|
|
|
|
mempty = EdgeCounts 0 0
|
|
|
|
|
mappend = (<>)
|
|
|
|
|
|
2018-06-20 19:27:42 +03:00
|
|
|
|
sortAndGroupBy :: Ord b => (a -> b) -> [a] -> [NonEmpty a]
|
|
|
|
|
sortAndGroupBy by = map NonEmpty.fromList . groupBy ((==) `on` by) . sortBy (comparing by)
|
2018-06-18 16:34:21 +03:00
|
|
|
|
|
|
|
|
|
|
2018-05-11 19:15:28 +03:00
|
|
|
|
instance Lower (Graph vertex) where
|
|
|
|
|
lowerBound = Class.empty
|
|
|
|
|
|
2018-05-11 19:12:05 +03:00
|
|
|
|
instance Semigroup (Graph vertex) where
|
2018-05-11 19:10:59 +03:00
|
|
|
|
(<>) = Class.overlay
|
2018-05-11 19:11:03 +03:00
|
|
|
|
|
2018-05-11 19:12:05 +03:00
|
|
|
|
instance Monoid (Graph vertex) where
|
2018-05-11 19:11:03 +03:00
|
|
|
|
mempty = Class.empty
|
|
|
|
|
mappend = (<>)
|
2018-05-11 19:11:49 +03:00
|
|
|
|
|
2018-05-11 19:12:05 +03:00
|
|
|
|
instance Ord vertex => Ord (Graph vertex) where
|
2018-05-11 19:11:49 +03:00
|
|
|
|
compare (Graph G.Empty) (Graph G.Empty) = EQ
|
|
|
|
|
compare (Graph G.Empty) _ = LT
|
|
|
|
|
compare _ (Graph G.Empty) = GT
|
|
|
|
|
compare (Graph (G.Vertex a)) (Graph (G.Vertex b)) = compare a b
|
|
|
|
|
compare (Graph (G.Vertex _)) _ = LT
|
|
|
|
|
compare _ (Graph (G.Vertex _)) = GT
|
|
|
|
|
compare (Graph (G.Overlay a1 a2)) (Graph (G.Overlay b1 b2)) = (compare `on` Graph) a1 b1 <> (compare `on` Graph) a2 b2
|
|
|
|
|
compare (Graph (G.Overlay _ _)) _ = LT
|
|
|
|
|
compare _ (Graph (G.Overlay _ _)) = GT
|
|
|
|
|
compare (Graph (G.Connect a1 a2)) (Graph (G.Connect b1 b2)) = (compare `on` Graph) a1 b1 <> (compare `on` Graph) a2 b2
|
2018-05-11 19:22:11 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance (Ord vertex, ToJSON vertex) => ToJSON (Graph vertex) where
|
2018-05-11 19:34:09 +03:00
|
|
|
|
toJSON (Graph graph) = object ["vertices" .= G.vertexList graph, "edges" .= (JSONEdge <$> G.edgeList graph)]
|
|
|
|
|
toEncoding (Graph graph) = pairs ("vertices" .= G.vertexList graph <> "edges" .= (JSONEdge <$> G.edgeList graph))
|
|
|
|
|
|
|
|
|
|
newtype JSONEdge vertex = JSONEdge (vertex, vertex)
|
|
|
|
|
|
|
|
|
|
instance ToJSON vertex => ToJSON (JSONEdge vertex) where
|
|
|
|
|
toJSON (JSONEdge (a, b)) = object ["source" .= a, "target" .= b]
|
|
|
|
|
toEncoding (JSONEdge (a, b)) = pairs ("source" .= a <> "target" .= b)
|