Source file topological.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
module type G = sig
type t
module V : Sig.COMPARABLE
val iter_vertex : (V.t -> unit) -> t -> unit
val iter_succ : (V.t -> unit) -> t -> V.t -> unit
end
module Make(G: G) = struct
module Scc = Components.Make(G)
let fold f g acc =
let n, scc = Scc.scc g in
let vertices = Array.make n [] in
let edges = Array.make n [] in
let degree = Array.make n 0 in
let add_vertex x =
let ix = scc x in
vertices.(ix) <- x :: vertices.(ix);
let add_edge y =
let iy = scc y in
if ix <> iy then begin
edges.(ix) <- iy :: edges.(ix);
degree.(iy) <- degree.(iy) + 1
end
in
G.iter_succ add_edge g x
in
G.iter_vertex add_vertex g;
let todo = Queue.create () in
let rec walk acc =
if Queue.is_empty todo then
acc
else
let i = Queue.pop todo in
let acc = List.fold_right f vertices.(i) acc in
List.iter
(fun j ->
let d = degree.(j) in
assert (d > 0);
if d = 1 then Queue.push j todo else degree.(j) <- d-1)
edges.(i);
walk acc
in
for i = 0 to n-1 do if degree.(i) = 0 then Queue.push i todo done;
walk acc
let iter f g = fold (fun v () -> f v) g ()
end
module Make_stable(G: sig include G val in_degree : t -> V.t -> int end) =
struct
module H = Hashtbl.Make(G.V)
module C = Path.Check(G)
let choose ~old (v, n: G.V.t * int) =
let l, min = old in
if n = min then v :: l, n
else if n < min then [ v ], n
else old
module Q = struct
module S = Set.Make(G.V)
let create () = ref S.empty
let push v s = s := S.add v !s
let pop s =
let r = S.min_elt !s in
s := S.remove r !s;
r
let is_empty s = S.is_empty !s
let choose ~old new_ =
let l, n = choose ~old new_ in
List.sort G.V.compare l, n
end
let find_top_cycle checker vl =
let on_top_cycle v =
List.for_all
(fun v' ->
G.V.equal v v' ||
C.check_path checker v v' || not (C.check_path checker v' v))
vl
in
List.filter on_top_cycle vl
let fold f g acc =
let checker = C.create g in
let degree = H.create 97 in
let todo = Q.create () in
let push x =
H.remove degree x;
Q.push x todo
in
let add_vertex acc v =
G.iter_succ
(fun x->
try
let d = H.find degree x in
if d = 1 then push x else H.replace degree x (d-1)
with Not_found ->
())
g v;
f v acc in
let rec walk acc =
if Q.is_empty todo then
let min, _ =
H.fold (fun v d old -> Q.choose ~old (v, d)) degree ([], max_int)
in
match min with
| [] -> acc
| _ ->
let vl = find_top_cycle checker min in
List.iter (H.remove degree) vl;
let acc = List.fold_left add_vertex acc vl in
walk acc
else
let v = Q.pop todo in
let acc = add_vertex acc v in
walk acc
in
G.iter_vertex
(fun v ->
let d = G.in_degree g v in
if d = 0 then Q.push v todo
else H.add degree v d)
g;
walk acc
let iter f g = fold (fun v () -> f v) g ()
end