1
1
mirror of https://github.com/github/semantic.git synced 2024-12-27 17:05:33 +03:00
semantic/src/Data/Graph.hs

102 lines
3.5 KiB
Haskell
Raw Normal View History

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
, 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
import Data.List (groupBy, sortBy)
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 19:57:12 +03:00
-- | Sort a graphs vertices by the number of in-edges.
2018-06-25 20:02:37 +03:00
--
-- >>> topologicalSort (Class.path "ab")
-- ['b' :| "",'a' :| ""]
--
-- >>> topologicalSort (Class.path "abc")
-- ['c' :| "",'b' :| "",'a' :| ""]
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)
. Monoidal.pairs
. 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-20 19:20:26 +03:00
data EdgeCounts = EdgeCounts
{ inEdgeCount :: {-# UNPACK #-} !Int
, outEdgeCount :: {-# UNPACK #-} !Int
}
deriving (Eq, Ord, Show)
instance Semigroup EdgeCounts where
EdgeCounts in1 out1 <> EdgeCounts in2 out2 = EdgeCounts (in1 + in2) (out1 + out2)
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-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
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)