{- Module : Pangraph.FGL Description : Provides `convert` and `revert` to a `FGL` form. The function provides an conversion to FGL in the datatypes `Pangraph` uses. Users should convert the types as the see fit for example, convert `ByteString` to `Int`. -} {-# LANGUAGE OverloadedStrings #-} module Pangraph.FGL (convert, revert) where -- External Imports -- ByteString import Data.ByteString (ByteString) import Data.ByteString.Char8 (pack) -- FGL import qualified Data.Graph.Inductive.Graph as FGL -- Containers import Data.Set (Set) import qualified Data.Set as Set -- Prelude import Data.Maybe (fromJust) import Data.Monoid ((<>)) -- Local import Pangraph import Pangraph.Internal.ProtoGraph -- | Convert a Pangraph to Fgl types. convert :: Pangraph -> ([FGL.LNode ByteString], [FGL.LEdge Int]) convert p = let -- Create the set of VertexIDs for crossreference when generating FGL.LEdge vertexSet :: Set VertexID vertexSet = (Set.fromList . map vertexID . vertexList) p -- The list of labelled vertices fglVertices :: [(Int, VertexID)] fglVertices = zip [0..] (Set.toAscList vertexSet) -- A helper function for cross referencing a Pangraph Vertex in its order in the set. This index forms a key in FGL. findIndexOfVertex :: VertexID -> Int findIndexOfVertex v = Set.findIndex v vertexSet -- Find the FGL.Node of the Endpoints, using the Set in VertexID. -- Safely fromJust the edgeID as its emergence from a Pangraph type enforces it Just. -- The id is formed from the order in the list provided by `vertices` which are guaranteed to be unique by the pangraph type. fglEdges :: [(FGL.Node, FGL.Node, Int)] fglEdges = let in map ((\(e, (a,b)) -> (findIndexOfVertex a, findIndexOfVertex b, e)) . (\e -> ((fromJust . edgeID) e, edgeEndpoints e))) (edgeList p) in (fglVertices, fglEdges) -- (Int, ByteString) -> (Int, Int, Int) -- | Revert FGL types into Pangraph. revert :: ([FGL.LNode ByteString], [FGL.LEdge Int]) -> Maybe Pangraph revert t = let vf :: ProtoVertex -> VertexID vf v = (fromJust . lookup "id") (protoVertexAttributes v) ef :: ProtoEdge -> (VertexID, VertexID) ef e = let lookup' :: Value -> VertexID lookup' value = (fromJust . lookup value) (protoEdgeAttributes e) in (lookup' "source", lookup' "target") in buildPangraph (FGL t) vf ef newtype FGL = FGL ([FGL.LNode ByteString], [FGL.LEdge Int]) instance BuildPangraph FGL where getProtoVertex (FGL (ns, _)) = map (\n -> makeProtoVertex [("id", snd n)]) ns getProtoEdge (FGL (_, es)) = let ps :: Show a => a -> ByteString ps = pack . show -- Take the source and destination and construct the protoEdge in map (\(src, dst, _) -> makeProtoEdge [("source", "n" <> ps src), ("target", "n" <> ps dst)]) es