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
}
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 (,())
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
)
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)
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
otherN :: (Eq n) => n -> et n -> AdjType et n
toEdge :: n -> AdjType et n -> et n
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