Skip to content
This repository was archived by the owner on Oct 4, 2020. It is now read-only.

Commit 493e6e1

Browse files
committed
Differentiate between cyclic and acyclic components
1 parent 92d1bff commit 493e6e1

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,28 @@
88

99
data Graph k v where
1010

11+
data SCC v where
12+
13+
14+
### Type Class Instances
15+
16+
instance eqSCC :: (Eq v) => Eq (SCC v)
17+
18+
instance showSCC :: (Show v) => Show (SCC v)
19+
1120

1221
### Values
1322

14-
scc :: forall v. (Eq v, Ord v) => Graph v v -> [[v]]
23+
scc :: forall v. (Eq v, Ord v) => Graph v v -> [SCC v]
1524

16-
scc' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [[v]]
25+
scc' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [SCC v]
1726

1827
topSort :: forall v. (Eq v, Ord v) => Graph v v -> [v]
1928

2029
topSort' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [v]
2130

31+
vertices :: forall v. SCC v -> [v]
32+
2233

2334
## Module Data.Map
2435

src/Data/Graph.purs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module Data.Graph (
22
Edge(..),
33
Graph(..),
4+
SCC(..),
5+
6+
vertices,
47

58
scc,
69
scc',
@@ -27,10 +30,26 @@ data Graph k v = Graph [v] [Edge k]
2730

2831
type Index = Number
2932

30-
scc :: forall v. (Eq v, Ord v) => Graph v v -> [[v]]
33+
data SCC v = AcyclicSCC v | CyclicSCC [v]
34+
35+
instance showSCC :: (Show v) => Show (SCC v) where
36+
show (AcyclicSCC v) = "AcyclicSCC (" ++ show v ++ ")"
37+
show (CyclicSCC vs) = "CyclicSCC " ++ show vs
38+
39+
instance eqSCC :: (Eq v) => Eq (SCC v) where
40+
(==) (AcyclicSCC v1) (AcyclicSCC v2) = v1 == v2
41+
(==) (CyclicSCC vs1) (CyclicSCC vs2) = vs1 == vs2
42+
(==) _ _ = false
43+
(/=) scc1 scc2 = not (scc1 == scc2)
44+
45+
vertices :: forall v. SCC v -> [v]
46+
vertices (AcyclicSCC v) = [v]
47+
vertices (CyclicSCC vs) = vs
48+
49+
scc :: forall v. (Eq v, Ord v) => Graph v v -> [SCC v]
3150
scc = scc' id id
3251

33-
scc' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [[v]]
52+
scc' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [SCC v]
3453
scc' makeKey makeVert (Graph vs es) = runPure (runST (do
3554
index <- newSTRef 0
3655
path <- newSTRef []
@@ -90,10 +109,15 @@ scc' makeKey makeVert (Graph vs es) = runPure (runST (do
90109
when (vIndex == vLowlink) $ do
91110
currentPath <- readSTRef path
92111
let newPath = popUntil makeKey v currentPath []
93-
modifySTRef components $ flip (++) [newPath.component]
112+
modifySTRef components $ flip (++) [makeComponent newPath.component]
94113
writeSTRef path newPath.path
95114
return {}
96-
in go vs)))
115+
116+
makeComponent [v] | not (isCycle (makeKey v)) = AcyclicSCC v
117+
makeComponent vs = CyclicSCC vs
118+
119+
isCycle k = any (\(Edge k1 k2) -> k1 == k && k2 == k) es
120+
in go vs)))
97121

98122
popUntil :: forall k v. (Eq k) => (v -> k) -> v -> [v] -> [v] -> { path :: [v], component :: [v] }
99123
popUntil _ _ [] popped = { path: [], component: popped }
@@ -111,4 +135,4 @@ topSort :: forall v. (Eq v, Ord v) => Graph v v -> [v]
111135
topSort = topSort' id id
112136

113137
topSort' :: forall k v. (Eq k, Ord k) => (v -> k) -> (k -> v) -> Graph k v -> [v]
114-
topSort' makeKey makeVert = reverse <<< concatMap id <<< scc' makeKey makeVert
138+
topSort' makeKey makeVert = reverse <<< concatMap vertices <<< scc' makeKey makeVert

tests/Tests.purs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,22 @@ main = do
9797
trace "testOneVertex"
9898
quickCheck $ \v -> let g = Graph ([v] :: [Number]) [] in
9999
let comps = scc g in
100-
comps == [[v]]
100+
comps == [AcyclicSCC v]
101+
102+
trace "testOneVertexCycle"
103+
quickCheck $ \v -> let g = Graph ([v] :: [Number]) [Edge v v] in
104+
let comps = scc g in
105+
comps == [CyclicSCC [v]]
101106

102107
trace "testOneComponent"
103108
quickCheck $ \v1 v2 -> let g = Graph ([v1, v2] :: [Number]) [Edge v1 v2, Edge v2 v1] in
104109
let comps = scc g in
105-
comps == [[v1, v2]] || comps == [[v2, v1]]
110+
comps == [CyclicSCC [v1, v2]] || comps == [CyclicSCC [v2, v1]]
106111

107112
trace "testTwoComponents"
108113
quickCheck $ \v1 v2 -> let g = Graph ([v1, v2] :: [Number]) [] in
109114
let comps = scc g in
110-
comps == [[v1], [v2]] || comps == [[v2], [v1]]
115+
comps == [AcyclicSCC v1, AcyclicSCC v2] || comps == [AcyclicSCC v2, AcyclicSCC v1]
111116

112117
trace "testManyEdges"
113118
quickCheck $ \vs -> let g = Graph (vs :: [Number]) (Edge <$> vs <*> vs) in
@@ -119,7 +124,7 @@ main = do
119124

120125
trace "testChain"
121126
quickCheck $ \vs -> let g = Graph (vs :: [Number]) (reverse $ chain vs) in
122-
scc g == reverse (map singleton vs)
127+
scc g == reverse (map AcyclicSCC vs)
123128

124129
chain :: forall v. [v] -> [Edge v]
125130
chain [] = []

0 commit comments

Comments
 (0)