{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} module Pangraph ( -- * Abstract Types Pangraph, Edge, Vertex, Attribute, Key, Value, VertexID, EdgeID, -- * Constructors makePangraph, makeEdge, makeVertex, -- * Pangraph Getters edgeList, vertexList, lookupVertex, lookupEdge, -- * Getters on Vertex and Edge edgeAttributes, vertexAttributes, edgeEndpoints, edgeID, vertexID ) where import Data.Maybe (mapMaybe) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import qualified Data.ByteString as BS import qualified Algebra.Graph.Class as Alga -- | The 'Pangraph' type is the core intermediate type between abstract representations of graphs. data Pangraph = Pangraph { vertices' :: Map VertexID Vertex , edges' :: Map EdgeID Edge } deriving (Eq) -- | A Vertex holds ['Attribute'] and must have a unique 'VertexID' to be constructed with 'makeVertex'. data Vertex = Vertex { vertexID' :: VertexID , vertexAttributes' :: [Attribute] } deriving (Eq) -- | Edges also reqiure ['Attribute'] and a tuple of 'Vertex' passed as connections to be constructed with 'makeEdge' data Edge = Edge { edgeID' :: Maybe EdgeID , edgeAttributes' :: [Attribute] , endpoints' :: (Vertex, Vertex) } deriving (Eq) -- | A type exposed for lookup in the resulting lists. type EdgeID = Int -- | A field that is Maybe internally is exposed for lookup. type VertexID = BS.ByteString -- | The type alias for storage of fields. type Attribute = (Key, Value) -- | The 'Key' in the tuple that makes up 'Attribute'. type Key = BS.ByteString -- | The 'Value' in the tuple that makes up 'Attribute'. type Value = BS.ByteString type MalformedEdge = (Edge, (Maybe Vertex, Maybe Vertex)) instance Show Pangraph where show p = "makePangraph " ++ show (Map.elems (vertices' p)) ++ " " ++ show (Map.elems (edges' p)) instance Show Vertex where show (Vertex i as) = unwords ["makeVertex", show i, show as] instance Show Edge where show (Edge _ as e) = unwords ["makeEdge", show as, show e] instance Alga.ToGraph Pangraph where type ToVertex Pangraph = Vertex toGraph p = Alga.graph (vertexList p) (map edgeEndpoints $ edgeList p) -- * List based constructors -- | Takes lists of 'Vertex' and 'Edge' to produce 'Just Pangraph' if the graph is correctly formed. makePangraph :: [Vertex] -> [Edge] -> Maybe Pangraph makePangraph vs es = case verifyGraph vertexMap es of [] -> Just $ Pangraph vertexMap edgeMap _ -> Nothing where vertexMap :: Map VertexID Vertex vertexMap = Map.fromList $ zip (map vertexID vs) vs edgeMap :: Map EdgeID Edge edgeMap = Map.fromList indexEdges indexEdges :: [(EdgeID, Edge)] indexEdges = map (\ (i, Edge _ as a) -> (i, Edge (Just i) as a )) $ zip [0..] es verifyGraph :: Map VertexID Vertex -> [Edge] -> [MalformedEdge] verifyGraph vs = mapMaybe (\e -> lookupEndpoints (e, edgeEndpoints e)) where lookupEndpoints :: (Edge, (Vertex, Vertex)) -> Maybe MalformedEdge lookupEndpoints (e, (v1,v2)) = case (Map.lookup (vertexID v1) vs, Map.lookup (vertexID v2) vs) of (Just _ , Just _) -> Nothing (Nothing, Just _) -> Just (e, (Just v1, Nothing)) (Just _ , Nothing) -> Just (e, (Nothing, Just v2)) (Nothing, Nothing) -> Just (e, (Just v1, Just v2)) -- | Edge constructor makeEdge :: [Attribute] -> (Vertex, Vertex) -> Edge makeEdge = Edge Nothing -- | Vertex constructor makeVertex :: VertexID -> [Attribute] -> Vertex makeVertex = Vertex -- * Pangraph Getters -- | Returns the ['Edge'] from a 'Pangraph' instance edgeList :: Pangraph -> [Edge] edgeList p = Map.elems $ edges' p -- | Returns the ['Vertex'] from a 'Pangraph' instance vertexList :: Pangraph -> [Vertex] vertexList p = Map.elems $ vertices' p -- | Lookup of the 'EdgeID' in a 'Pangraph'. Complexity: /O(log n)/ lookupEdge :: EdgeID -> Pangraph -> Maybe Edge lookupEdge key p = Map.lookup key $ edges' p -- | Lookup of the 'VertexID' in a 'Pangraph'. Complexity: /O(log n)/ lookupVertex :: VertexID -> Pangraph -> Maybe Vertex lookupVertex key p = Map.lookup key $ vertices' p -- * Getters on 'Edge' and 'Vertex' -- | Returns the ['Attribute'] of an 'Edge' edgeAttributes :: Edge -> [Attribute] edgeAttributes = edgeAttributes' -- | Returns the ['Attribute'] list of an 'Edge' vertexAttributes :: Vertex -> [Attribute] vertexAttributes = vertexAttributes' -- | Returns the endpoint of tupled 'Vertex' of an 'Edge' edgeEndpoints :: Edge -> (Vertex, Vertex) edgeEndpoints = endpoints' -- | Returns the EdgeID if it has one. 'Edge's are given a new 'EdgeID' when they are passed and retrived from a 'Pangraph' edgeID :: Edge -> Maybe EdgeID edgeID = edgeID' -- | Returns a 'VertexID' vertexID :: Vertex -> VertexID vertexID = vertexID'