1{-# LANGUAGE CPP #-}
2#if __GLASGOW_HASKELL__ >= 702
3{-# LANGUAGE DeriveGeneric #-}
4#endif
5
6-- (c) 1999 - 2002 by Martin Erwig [see file COPYRIGHT]
7-- | Tree-based implementation of 'Graph' and 'DynGraph'
8--
9-- You will probably have better performance using the
10-- "Data.Graph.Inductive.PatriciaTree" implementation instead.
11
12module Data.Graph.Inductive.Tree (Gr,UGr) where
13
14import Data.Graph.Inductive.Graph
15
16import Control.Applicative (liftA2)
17import Data.List (foldl', sort)
18import Data.Map (Map)
19import qualified Data.Map as M
20import Data.Maybe (fromMaybe)
21
22#if MIN_VERSION_containers (0,4,2)
23import Control.DeepSeq (NFData (..))
24#endif
25
26#if __GLASGOW_HASKELL__ >= 702
27import GHC.Generics (Generic)
28#endif
29
30#if MIN_VERSION_base (4,8,0)
31import Data.Bifunctor
32#else
33import Control.Arrow (first, second)
34#endif
35
36----------------------------------------------------------------------
37-- GRAPH REPRESENTATION
38----------------------------------------------------------------------
39
40newtype Gr a b = Gr (GraphRep a b)
41#if __GLASGOW_HASKELL__ >= 702
42 deriving (Generic)
43#endif
44
45type GraphRep a b = Map Node (Context' a b)
46type Context' a b = (Adj b,a,Adj b)
47
48type UGr = Gr () ()
49
50----------------------------------------------------------------------
51-- CLASS INSTANCES
52----------------------------------------------------------------------
53
54instance (Eq a, Ord b) => Eq (Gr a b) where
55 (Gr g1) == (Gr g2) = fmap sortAdj g1 == fmap sortAdj g2
56 where
57 sortAdj (p,n,s) = (sort p,n,sort s)
58
59instance (Show a, Show b) => Show (Gr a b) where
60 showsPrec d g = showParen (d > 10) $
61 showString "mkGraph "
62 . shows (labNodes g)
63 . showString " "
64 . shows (labEdges g)
65
66instance (Read a, Read b) => Read (Gr a b) where
67 readsPrec p = readParen (p > 10) $ \ r -> do
68 ("mkGraph", s) <- lex r
69 (ns,t) <- reads s
70 (es,u) <- reads t
71 return (mkGraph ns es, u)
72
73-- Graph
74--
75instance Graph Gr where
76 empty = Gr M.empty
77
78 isEmpty (Gr g) = M.null g
79
80 match v gr@(Gr g) = maybe (Nothing, gr)
81 (first Just . uncurry (cleanSplit v))
82 . (\(m,g') -> fmap (flip (,) g') m)
83 $ M.updateLookupWithKey (const (const Nothing)) v g
84
85 mkGraph vs es = insEdges es
86 . Gr
87 . M.fromList
88 . map (second (\l -> ([],l,[])))
89 $ vs
90
91 labNodes (Gr g) = map (\(v,(_,l,_))->(v,l)) (M.toList g)
92
93 matchAny (Gr g) = maybe (error "Match Exception, Empty Graph")
94 (uncurry (uncurry cleanSplit))
95 (M.minViewWithKey g)
96
97 noNodes (Gr g) = M.size g
98
99 nodeRange (Gr g) = fromMaybe (error "nodeRange of empty graph")
100 $ liftA2 (,) (ix (M.minViewWithKey g))
101 (ix (M.maxViewWithKey g))
102 where
103 ix = fmap (fst . fst)
104
105 labEdges (Gr g) = concatMap (\(v,(_,_,s))->map (\(l,w)->(v,w,l)) s) (M.toList g)
106
107-- After a Node (with its corresponding Context') are split out of a
108-- GraphRep, clean up the remainders.
109cleanSplit :: Node -> Context' a b -> GraphRep a b
110 -> (Context a b, Gr a b)
111cleanSplit v (p,l,s) g = (c, Gr g')
112 where
113 -- Note: loops are kept only in successor list
114 c = (p', v, l, s)
115 p' = rmLoops p
116 s' = rmLoops s
117 rmLoops = filter ((/=v) . snd)
118
119 g' = updAdj s' (clearPred v) . updAdj p' (clearSucc v) $ g
120
121-- DynGraph
122--
123instance DynGraph Gr where
124 (p,v,l,s) & (Gr g) = Gr
125 . updAdj p (addSucc v)
126 . updAdj s (addPred v)
127 $ M.alter addCntxt v g
128 where
129 addCntxt = maybe (Just cntxt')
130 (const (error ("Node Exception, Node: "++show v)))
131 cntxt' = (p,l,s)
132
133#if MIN_VERSION_containers (0,4,2)
134instance (NFData a, NFData b) => NFData (Gr a b) where
135 rnf (Gr g) = rnf g
136#endif
137
138instance Functor (Gr a) where
139 fmap = emap
140
141#if MIN_VERSION_base (4,8,0)
142instance Bifunctor Gr where
143 bimap = nemap
144
145 first = nmap
146
147 second = emap
148#endif
149
150----------------------------------------------------------------------
151-- UTILITIES
152----------------------------------------------------------------------
153
154addSucc :: Node -> b -> Context' a b -> Context' a b
155addSucc v l (p,l',s) = (p,l',(l,v):s)
156
157addPred :: Node -> b -> Context' a b -> Context' a b
158addPred v l (p,l',s) = ((l,v):p,l',s)
159
160clearSucc :: Node -> b -> Context' a b -> Context' a b
161clearSucc v _ (p,l,s) = (p,l,filter ((/=v).snd) s)
162
163clearPred :: Node -> b -> Context' a b -> Context' a b
164clearPred v _ (p,l,s) = (filter ((/=v).snd) p,l,s)
165
166updAdj :: Adj b -> (b -> Context' a b -> Context' a b) -> GraphRep a b -> GraphRep a b
167updAdj adj f g = foldl' (\g' (l,v) -> M.adjust (f l) v g') g adj