Skip to content

Commit bb65f5c

Browse files
committed
Use differenceWith to implement (&) and match
Based upon work by David Feuer, manually re-integrated into current codebase. Closes #48; closes #39.
1 parent 06ce186 commit bb65f5c

File tree

1 file changed

+79
-35
lines changed

1 file changed

+79
-35
lines changed

Data/Graph/Inductive/PatriciaTree.hs

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,17 @@ import Data.Graph.Inductive.Graph
3030
import Control.Applicative (liftA2)
3131
import Data.IntMap (IntMap)
3232
import qualified Data.IntMap as IM
33-
import Data.List (sort)
33+
import Data.List (foldl', sort)
3434
import Data.Maybe (fromMaybe)
3535

3636
#if MIN_VERSION_containers (0,4,2)
37-
import Control.DeepSeq (NFData (..))
37+
import Control.DeepSeq (NFData(..))
38+
#endif
39+
40+
#if MIN_VERSION_containers(0,5,0)
41+
import qualified Data.IntMap.Strict as IMS
42+
#else
43+
import qualified Data.IntMap as IMS
3844
#endif
3945

4046
#if __GLASGOW_HASKELL__ >= 702
@@ -115,9 +121,11 @@ instance Graph Gr where
115121

116122
instance DynGraph Gr where
117123
(p, v, l, s) & (Gr g)
118-
= let !g1 = IM.insert v (fromAdj p, l, fromAdj s) g
119-
!g2 = addSucc g1 v p
120-
!g3 = addPred g2 v s
124+
= let !g1 = IM.insert v (preds, l, succs) g
125+
!(np, preds) = fromAdjCounting p
126+
!(ns, succs) = fromAdjCounting s
127+
!g2 = addSucc g1 v np preds
128+
!g3 = addPred g2 v ns succs
121129
in Gr g3
122130

123131
#if MIN_VERSION_containers (0,4,2)
@@ -144,8 +152,8 @@ matchGr node (Gr g)
144152
-> let !g1 = IM.delete node g
145153
!p' = IM.delete node p
146154
!s' = IM.delete node s
147-
!g2 = clearPred g1 node (IM.keys s')
148-
!g3 = clearSucc g2 node (IM.keys p')
155+
!g2 = clearPred g1 node s'
156+
!g3 = clearSucc g2 node p'
149157
in (Just (toAdj p', node, label, toAdj s), Gr g3)
150158

151159
----------------------------------------------------------------------
@@ -166,11 +174,11 @@ fastInsNode (v, l) (Gr g) = g' `seq` Gr g'
166174
fastInsEdge :: LEdge b -> Gr a b -> Gr a b
167175
fastInsEdge (v, w, l) (Gr g) = g2 `seq` Gr g2
168176
where
169-
g1 = IM.adjust addSucc' v g
170-
g2 = IM.adjust addPred' w g1
177+
g1 = IM.adjust addS' v g
178+
g2 = IM.adjust addP' w g1
171179

172-
addSucc' (ps, l', ss) = (ps, l', IM.insertWith addLists w [l] ss)
173-
addPred' (ps, l', ss) = (IM.insertWith addLists v [l] ps, l', ss)
180+
addS' (ps, l', ss) = (ps, l', IM.insertWith addLists w [l] ss)
181+
addP' (ps, l', ss) = (IM.insertWith addLists v [l] ps, l', ss)
174182

175183
{-# RULES
176184
"gmap/Data.Graph.Inductive.PatriciaTree" gmap = fastGMap
@@ -220,6 +228,31 @@ toAdj = concatMap expand . IM.toList
220228
fromAdj :: Adj b -> IntMap [b]
221229
fromAdj = IM.fromListWith addLists . map (second (:[]) . swap)
222230

231+
data FromListCounting a = FromListCounting !Int !(IntMap a)
232+
deriving (Eq, Show, Read)
233+
234+
getFromListCounting :: FromListCounting a -> (Int, IntMap a)
235+
getFromListCounting (FromListCounting i m) = (i, m)
236+
{-# INLINE getFromListCounting #-}
237+
238+
fromListWithKeyCounting :: (Int -> a -> a -> a) -> [(Int, a)] -> (Int, IntMap a)
239+
fromListWithKeyCounting f = getFromListCounting . foldl' ins (FromListCounting 0 IM.empty)
240+
where
241+
ins (FromListCounting i t) (k,x) = FromListCounting (i + 1) (IM.insertWithKey f k x t)
242+
{-# INLINE fromListWithKeyCounting #-}
243+
244+
fromListWithCounting :: (a -> a -> a) -> [(Int, a)] -> (Int, IntMap a)
245+
fromListWithCounting f = fromListWithKeyCounting (\_ x y -> f x y)
246+
{-# INLINE fromListWithCounting #-}
247+
248+
fromAdjCounting :: Adj b -> (Int, IntMap [b])
249+
fromAdjCounting = fromListWithCounting addLists . map (second (:[]) . swap)
250+
251+
-- We use differenceWith to modify a graph more than bulkThreshold times,
252+
-- and repeated insertWith otherwise.
253+
bulkThreshold :: Int
254+
bulkThreshold = 5
255+
223256
toContext :: Node -> Context' a b -> Context a b
224257
toContext v (ps, a, ss) = (toAdj ps, v, a, toAdj ss)
225258

@@ -238,33 +271,44 @@ addLists [a] as = a : as
238271
addLists as [a] = a : as
239272
addLists xs ys = xs ++ ys
240273

241-
addSucc :: GraphRep a b -> Node -> [(b, Node)] -> GraphRep a b
242-
addSucc g _ [] = g
243-
addSucc g v ((l, p) : rest) = addSucc g' v rest
244-
where
245-
g' = IM.adjust f p g
246-
f (ps, l', ss) = (ps, l', IM.insertWith addLists v [l] ss)
247-
248-
249-
addPred :: GraphRep a b -> Node -> [(b, Node)] -> GraphRep a b
250-
addPred g _ [] = g
251-
addPred g v ((l, s) : rest) = addPred g' v rest
274+
addSucc :: forall a b . GraphRep a b -> Node -> Int -> IM.IntMap [b] -> GraphRep a b
275+
addSucc g0 v numAdd xs
276+
| numAdd < bulkThreshold = IM.foldlWithKey' go g0 xs
252277
where
253-
g' = IM.adjust f s g
254-
f (ps, l', ss) = (IM.insertWith addLists v [l] ps, l', ss)
255-
278+
go :: GraphRep a b -> Node -> [b] -> GraphRep a b
279+
go g p l = IMS.adjust f p g
280+
where f (ps, l', ss) = let !ss' = IM.insertWith (++) v l ss
281+
in (ps, l', ss')
282+
addSucc g v _ xs = IMS.differenceWith go g xs
283+
where
284+
go :: Context' a b -> [b] -> Maybe (Context' a b)
285+
go (ps, l', ss) l = let !ss' = IM.insertWith (++) v l ss
286+
in Just (ps, l', ss')
256287

257-
clearSucc :: GraphRep a b -> Node -> [Node] -> GraphRep a b
258-
clearSucc g _ [] = g
259-
clearSucc g v (p:rest) = clearSucc g' v rest
288+
addPred :: forall a b . GraphRep a b -> Node -> Int -> IM.IntMap [b] -> GraphRep a b
289+
addPred g0 v numAdd xs
290+
| numAdd < bulkThreshold = IM.foldlWithKey' go g0 xs
260291
where
261-
g' = IM.adjust f p g
262-
f (ps, l, ss) = (ps, l, IM.delete v ss)
292+
go :: GraphRep a b -> Node -> [b] -> GraphRep a b
293+
go g p l = IMS.adjust f p g
294+
where f (ps, l', ss) = let !ps' = IM.insertWith (++) v l ps
295+
in (ps', l', ss)
296+
addPred g v _ xs = IMS.differenceWith go g xs
297+
where
298+
go :: Context' a b -> [b] -> Maybe (Context' a b)
299+
go (ps, l', ss) l = let !ps' = IM.insertWith (++) v l ps
300+
in Just (ps', l', ss)
263301

302+
clearSucc :: forall a b x . GraphRep a b -> Node -> IM.IntMap x -> GraphRep a b
303+
clearSucc g v = IMS.differenceWith go g
304+
where
305+
go :: Context' a b -> x -> Maybe (Context' a b)
306+
go (ps, l, ss) _ = let !ss' = IM.delete v ss
307+
in Just (ps, l, ss')
264308

265-
clearPred :: GraphRep a b -> Node -> [Node] -> GraphRep a b
266-
clearPred g _ [] = g
267-
clearPred g v (s:rest) = clearPred g' v rest
309+
clearPred :: forall a b x . GraphRep a b -> Node -> IM.IntMap x -> GraphRep a b
310+
clearPred g v = IMS.differenceWith go g
268311
where
269-
g' = IM.adjust f s g
270-
f (ps, l, ss) = (IM.delete v ps, l, ss)
312+
go :: Context' a b -> x -> Maybe (Context' a b)
313+
go (ps, l, ss) _ = let !ps' = IM.delete v ps
314+
in Just (ps', l, ss)

0 commit comments

Comments
 (0)