-
Notifications
You must be signed in to change notification settings - Fork 0
/
topo_sort.ML
114 lines (103 loc) · 3.1 KB
/
topo_sort.ML
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
107
108
109
110
111
112
113
114
(*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*)
signature TOPO_SORT =
sig
val topo_sort : {cmp: 'a * 'a -> order, graph : 'a -> 'a list,
converse : 'a -> 'a list} ->
'a list ->
'a list list
(* a "topological sort" that sorts the graph into topologically ordered
strongly connected components, using Tarjan's algorithm. *)
end
structure Topo_Sort : TOPO_SORT =
struct
fun dfs_finishes (cmp, neighbours) nodes = let
datatype 'a action = Visit of 'a | Finish of 'a
fun recurse visited result actlist =
case actlist of
[] => result
| Visit n :: rest => if Binaryset.member(visited, n) then
recurse visited result rest
else let
val ns = map Visit (neighbours n)
in
recurse (Binaryset.add(visited, n))
result
(ns @ (Finish n :: rest))
end
| Finish n :: rest => recurse visited (n::result) rest
in
recurse (Binaryset.empty cmp) [] (map Visit nodes)
end
fun fcons _ [] = raise Fail "Should never happen"
| fcons x (h::t) = (x::h) :: t
fun dfs_trees (cmp, neighbours) nodes = let
datatype 'a action = Visit of 'a | Initial of 'a
fun recurse visited result actlist =
case actlist of
[] => result
| Initial n :: rest => if Binaryset.member(visited,n) then
recurse visited result rest
else
recurse (Binaryset.add(visited, n))
([n] :: result)
(map Visit (neighbours n) @ rest)
| Visit n :: rest => if Binaryset.member(visited, n) then
recurse visited result rest
else
recurse (Binaryset.add(visited, n))
(fcons n result)
(map Visit (neighbours n) @ rest)
in
recurse (Binaryset.empty cmp) [] (map Initial nodes)
end
fun topo_sort {cmp, graph, converse} nodes =
dfs_trees (cmp, converse) (dfs_finishes (cmp, graph) nodes)
(*
fun ns 0 = [1]
| ns 1 = [2,3]
| ns 2 = []
| ns 3 = [5,7]
| ns 4 = []
| ns 5 = [8,9]
| ns 6 = []
| ns 7 = [3,4,6]
| ns 8 = [5]
| ns 9 = [];
fun ns' 0 = []
| ns' 1 = [0]
| ns' 2 = [1]
| ns' 3 = [1,7]
| ns' 4 = [7]
| ns' 5 = [3,8]
| ns' 6 = [7]
| ns' 7 = [3]
| ns' 8 = [5]
| ns' 9 = [5];
fun eg235 n =
case n of
1 => [2]
| 2 => [3,5,6]
| 3 => [4,7]
| 4 => [3,8]
| 5 => [1,6]
| 6 => [7]
| 7 => [6,8]
| 8 => [8]
fun eg235' n =
case n of
1 => [5]
| 2 => [1]
| 3 => [2,4]
| 4 => [3]
| 5 => [2]
| 6 => [2,5,7]
| 7 => [3,6]
| 8 => [8]
val sscs = dfs_trees (Int.compare, eg235')
(dfs_finishes (Int.compare, eg235) [1,2,3,4,5,6,7,8])
*)
end; (* struct *)