{-# LANGUAGE ConstraintKinds, FlexibleContexts, GeneralizedNewtypeDeriving, MultiParamTypeClasses, TupleSections, TypeFamilies #-} {- | Module : Data.Graph.Unordered.Internal Description : Internal data definition Copyright : (c) Ivan Lazar Miljenovic License : MIT Maintainer : Ivan.Miljenovic@gmail.com -} module Data.Graph.Unordered.Internal where import Control.Arrow (first, second) import Control.DeepSeq (NFData (..)) import Data.Functor.Identity import Data.Hashable (Hashable) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM import Data.List (foldl') -- ----------------------------------------------------------------------------- data Graph et n nl el = Gr { nodeMap :: !(NodeMap n nl) , edgeMap :: !(EdgeMap et n el) , nextEdge :: !Edge } -- NOTE: we don't include nextEdge in equality tests. instance (Eq (et n), Eq n, Eq nl, Eq el) => Eq (Graph et n nl el) where g1 == g2 = nodeMap g1 == nodeMap g2 && edgeMap g1 == edgeMap g2 instance (EdgeType et, Show n, Show nl, Show el) => Show (Graph et n nl el) where showsPrec d g = showParen (d > 10) $ showString "mkGraph " . shows (lnodes g) . showString " " . shows (ledgePairs g) instance (ValidGraph et n, Read n, Read nl, Read el) => Read (Graph et n nl el) where readsPrec p = readParen (p > 10) $ \r -> do ("mkGraph", s) <- lex r (ns,t) <- reads s (es,u) <- reads t return (mkGraph ns es, u) instance (NFData n, NFData (et n), NFData nl, NFData el) => NFData (Graph et n nl el) where rnf (Gr nm em ne) = rnf nm `seq` rnf em `seq` rnf ne type NodeMap n nl = HashMap n (Adj, nl) type EdgeMap et n el = HashMap Edge (et n, el) newtype Edge = Edge { unEdge :: Word } deriving (Eq, Ord, Show, Read, Hashable, Enum, Bounded, NFData) type Set n = HashMap n () mkSet :: (Eq n, Hashable n) => [n] -> Set n mkSet = HM.fromList . map (,()) -- The Int value is used for how many times that edge is attached to -- the node: 1 for normal edges, 2 for loops. -- -- If we change this to being a list, then the Eq instance for Graph can't be derived. type Adj = HashMap Edge Int adjCount :: (Eq n) => n -> n -> Int adjCount u v | u == v = 2 | otherwise = 1 type ValidGraph et n = (Hashable n ,Eq n ,EdgeType et ) -- | Assumes all nodes are in the node list. mkGraph :: (ValidGraph et n) => [(n,nl)] -> [(n,n,el)] -> Graph et n nl el mkGraph nlk elk = Gr nM eM nextE where addEs = zip [minBound..] elk eM = HM.fromList . map (second toE) $ addEs toE (u,v,el) = (mkEdge u v, el) adjs = foldl' (HM.unionWith HM.union) HM.empty (concatMap toAdjM addEs) toAdjM (e,(u,v,_)) = [toA u, toA v] where toA n = HM.singleton n (HM.singleton e (adjCount u v)) nM = HM.mapWithKey (\n nl -> (HM.lookupDefault HM.empty n adjs, nl)) (HM.fromList nlk) -- TODO: can this be derived more efficiently? Consider defining -- an alternate definition of zip... nextE | null addEs = minBound | otherwise = succ . fst $ last addEs -- ----------------------------------------------------------------------------- class (Functor et, NodeFrom (AdjType et)) => EdgeType et where type AdjType et :: * -> * mkEdge :: n -> n -> et n -- | Assumes @n@ is one of the end points of this edge. otherN :: (Eq n) => n -> et n -> AdjType et n toEdge :: n -> AdjType et n -> et n -- | Returns a list of length 2. edgeNodes :: et n -> [n] edgeTriple :: (et n, el) -> (n, n, el) class NodeFrom at where getNode :: at n -> n instance NodeFrom Identity where getNode = runIdentity -- ----------------------------------------------------------------------------- nodeDetails :: Graph et n nl el -> [(n, ([Edge], nl))] nodeDetails = map (second (first (concatMap (uncurry $ flip replicate) . HM.toList))) . HM.toList . nodeMap lnodes :: Graph et n nl el -> [(n,nl)] lnodes = map (second snd) . nodeDetails edges :: Graph et n nl el -> [Edge] edges = HM.keys . edgeMap edgeDetails :: Graph et n nl el -> [(Edge, (et n, el))] edgeDetails = HM.toList . edgeMap ledges :: Graph et n nl el -> [(Edge, el)] ledges = map (second snd) . edgeDetails edgePairs :: (EdgeType et) => Graph et n nl el -> [(n, n)] edgePairs = map (ePair . fst) . HM.elems . edgeMap where ePair et = let [u,v] = edgeNodes et in (u,v) ledgePairs :: (EdgeType et) => Graph et n nl el -> [(n,n,el)] ledgePairs = map eTriple . HM.elems . edgeMap where eTriple (et,el) = let [u,v] = edgeNodes et in (u,v,el) -- ----------------------------------------------------------------------------- degNM :: (Eq n, Hashable n) => NodeMap n nl -> n -> Int degNM nm = maybe 0 (sum . HM.elems . fst) . (`HM.lookup` nm) -- ----------------------------------------------------------------------------- withNodeMap :: (NodeMap n nl -> NodeMap n nl') -> Graph et n nl el -> Graph et n nl' el withNodeMap f (Gr nm em e) = Gr (f nm) em e withEdgeMap :: (EdgeMap et n el -> EdgeMap et n el') -> Graph et n nl el -> Graph et n nl el' withEdgeMap f (Gr nm em e) = Gr nm (f em) e