-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathTopSort.hs
More file actions
106 lines (91 loc) · 3.78 KB
/
Copy pathTopSort.hs
File metadata and controls
106 lines (91 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE MagicHash #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# OPTIONS_GHC -Wno-unused-matches #-}
module Data.HashMap.Mutable.TopSort where
import Data.Bifunctor.Linear (second)
import qualified Data.Functor.Linear as Data
import Data.HashMap.Mutable.Linear (HashMap)
import qualified Data.HashMap.Mutable.Linear as HMap
import Data.Maybe.Linear (catMaybes)
import Data.Unrestricted.Linear
import qualified Prelude.Linear as Linear
-- # The topological sort of a DAG
-------------------------------------------------------------------------------
type Node = Int
type InDegGraph = HashMap Node ([Node], Int)
topsort :: [(Node, [Node])] -> [Node]
topsort = reverse . postOrder . fmap (\(n, nbrs) -> (n, (nbrs, 0)))
where
postOrder :: [(Node, ([Node], Int))] -> [Node]
postOrder [] = []
postOrder (xs) =
let nodes = map fst xs
in unur Linear.$
HMap.empty (length xs * 2) Linear.$
\hm -> postOrderHM nodes (HMap.insertAll xs hm)
postOrderHM :: [Node] -> InDegGraph %1 -> Ur [Node]
postOrderHM nodes dag =
case findSources nodes (computeInDeg nodes dag) of
(dag, Ur sources) -> pluckSources sources [] dag
where
-- O(V + N)
computeInDeg :: [Node] -> InDegGraph %1 -> InDegGraph
computeInDeg nodes dag = Linear.foldl incChildren dag (map Ur nodes)
-- Increment in-degree of all neighbors
incChildren :: InDegGraph %1 -> Ur Node %1 -> InDegGraph
incChildren dag (Ur node) =
case HMap.lookup node dag of
(Ur Nothing, dag) -> dag
(Ur (Just (xs, i)), dag) -> incNodes (move xs) dag
where
incNodes :: Ur [Node] %1 -> InDegGraph %1 -> InDegGraph
incNodes (Ur ns) dag = Linear.foldl incNode dag (map Ur ns)
incNode :: InDegGraph %1 -> Ur Node %1 -> InDegGraph
incNode dag (Ur node) =
case HMap.lookup node dag of
(Ur Nothing, dag') -> dag'
(Ur (Just (n, d)), dag') ->
HMap.insert node (n, d + 1) dag'
-- HMap.alter dag (\(Just (n,d)) -> Just (n,d+1)) node
-- pluckSources sources postOrdSoFar dag
pluckSources :: [Node] -> [Node] -> InDegGraph %1 -> Ur [Node]
pluckSources [] postOrd dag = lseq dag (move postOrd)
pluckSources (s : ss) postOrd dag =
case HMap.lookup s dag of
(Ur Nothing, dag) -> pluckSources ss (s : postOrd) dag
(Ur (Just (xs, i)), dag) ->
case walk xs dag of
(dag', Ur newSrcs) ->
pluckSources (newSrcs ++ ss) (s : postOrd) dag'
where
-- decrement degree of children, save newly made sources
walk :: [Node] -> InDegGraph %1 -> (InDegGraph, Ur [Node])
walk children dag =
second (Data.fmap catMaybes) (mapAccum decDegree children dag)
-- Decrement the degree of a node, save it if it is now a source
decDegree :: Node -> InDegGraph %1 -> (InDegGraph, Ur (Maybe Node))
decDegree node dag =
case HMap.lookup node dag of
(Ur Nothing, dag') -> (dag', Ur Nothing)
(Ur (Just (n, d)), dag') ->
checkSource node (HMap.insert node (n, d - 1) dag')
-- Given a list of nodes, determines which are sources
findSources :: [Node] -> InDegGraph %1 -> (InDegGraph, Ur [Node])
findSources nodes dag =
second (Data.fmap catMaybes) (mapAccum checkSource nodes dag)
-- | Check if a node is a source, and if so return it
checkSource :: Node -> InDegGraph %1 -> (InDegGraph, Ur (Maybe Node))
checkSource node dag =
case HMap.lookup node dag of
(Ur Nothing, dag) -> (dag, Ur Nothing)
(Ur (Just (xs, 0)), dag) -> (dag, Ur (Just node))
(Ur (Just (xs, n)), dag) -> (dag, Ur Nothing)
mapAccum ::
(a -> b %1 -> (b, Ur c)) -> [a] -> b %1 -> (b, Ur [c])
mapAccum f [] b = (b, Ur [])
mapAccum f (x : xs) b =
case mapAccum f xs b of
(b, Ur cs) -> second (Data.fmap (: cs)) (f x b)