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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
module type S = sig
type graph
type vertex
type edge
type edge_label
val merge_vertex: graph -> vertex list -> graph
val merge_edges_e:
?src:vertex -> ?dst:vertex -> graph -> edge list -> graph
val merge_edges_with_label:
?src:vertex -> ?dst:vertex -> ?label:edge_label -> graph -> edge_label
-> graph
val merge_isolabelled_edges: graph -> graph
val merge_ends: ?strict:bool -> ?specified_vertex:vertex -> graph -> graph
val merge_starts: ?strict:bool -> ?specified_vertex:vertex -> graph -> graph
val merge_scc:
?loop_killer:bool -> ?specified_vertex:(vertex list -> vertex) -> graph ->
graph
end
module B(B: Builder.S) = struct
type graph = B.G.t
type vertex = B.G.vertex
type edge = B.G.edge
type edge_label = B.G.E.label
let mem x ec = List.exists (fun y -> B.G.V.equal x y) ec
let identify x ec = match ec with
| [] -> false , x
| y :: ec -> if mem x ec then true, y else false, x
let identify_extremities g vl =
let f e accu =
let sx, x = identify (B.G.E.src e) vl in
let sy, y = identify (B.G.E.dst e) vl in
if sx || sy
then B.G.E.(create x (label e) y) :: accu
else accu
in
B.G.fold_edges_e f g []
let merge_vertex g vl = match vl with
| [] -> g
| v :: vl' ->
let to_be_added = identify_extremities g vl in
let g = List.fold_left B.remove_vertex g vl' in
if to_be_added = []
then B.add_vertex g v
else List.fold_left B.add_edge_e g to_be_added
let merge_edges_e ?src ?dst g el = match el with
| e :: el' ->
let el' = List.filter (B.G.mem_edge_e g) el' in
if el' <> []
then
(let el = e :: el' in
let extremities e = B.G.E.(src e, dst e) in
let sources , destinations = List.split (List.map extremities el) in
let remove accu e =
try B.remove_edge_e accu e
with Invalid_argument _ -> g in
let g = List.fold_left remove g el in
if List.exists (fun v -> mem v destinations) sources then
let v = match src with
| None ->
(match dst with
| None -> List.hd sources
| Some w -> w)
| Some v -> v in
let g = merge_vertex g (v :: sources @ destinations) in
B.add_edge_e g B.G.E.(create v (label e) v)
else
let v = match src with None -> List.hd sources | Some v -> v in
let w = match src with
| None -> List.hd destinations
| Some w -> w in
let g = merge_vertex g sources in
let g = merge_vertex g destinations in
B.add_edge_e g B.G.E.(create v (label e) w))
else g
| [] -> g
let merge_edges_with_label ?src ?dst ?label g l =
let update_label e = match label with
| None -> e
| Some l -> B.G.E.(create (src e) l (dst e))
in
let collect_edge e accu =
if B.G.E.label e = l
then (update_label e) :: accu
else accu
in
let edges_to_be_merged = B.G.fold_edges_e collect_edge g [] in
merge_edges_e ?src ?dst g edges_to_be_merged
let compare_label g =
try
let default_vertex =
let a_vertex_of_g = ref None in
(try B.G.iter_vertex (fun v -> a_vertex_of_g := Some v ; raise Exit) g
with Exit -> ());
match !a_vertex_of_g with
| Some v -> v
| None -> raise Exit in
fun l1 l2 ->
let e1 = B.G.E.create default_vertex l1 default_vertex in
let e2 = B.G.E.create default_vertex l2 default_vertex in
B.G.E.compare e1 e2
with Exit -> (fun _ _ -> 0)
let merge_isolabelled_edges g =
let module S = Set.Make(B.G.V) in
let do_meet s1 s2 = S.exists (fun x -> S.mem x s2) s1 in
let module M =
Map.Make(struct type t = B.G.E.label let compare = compare_label g end)
in
let accumulating e accu =
let l = B.G.E.label e in
try
let s , d = M.find l accu in
let s , d = B.G.E.(S.add (src e) s , S.add (dst e) d) in
M.add l (s, d) accu
with Not_found ->
M.add l B.G.E.(S.singleton (src e), S.singleton (dst e)) accu
in
let to_be_identified = B.G.fold_edges_e accumulating g M.empty in
let gathering _ (s, d) accu =
let to_be_gathered, others = List.partition (do_meet s) accu in
let accu =
List.fold_left (fun accu x -> S.union accu x) s to_be_gathered
:: others
in
let to_be_gathered , others = List.partition (do_meet d) accu in
List.fold_left (fun accu x -> S.union accu x) d to_be_gathered :: others
in
let to_be_identified = M.fold gathering to_be_identified [] in
List.fold_left
(fun accu s -> merge_vertex accu (S.elements s))
g
to_be_identified
let merge_ends ?(strict=false) ?specified_vertex g =
let accumulator v accu =
if
let out_d = B.G.out_degree g v in
out_d = 0 ||
((not strict) && out_d = List.length (B.G.find_all_edges g v v))
then v :: accu
else accu
in
let ends = B.G.(fold_vertex accumulator g []) in
let to_be_merged =
match specified_vertex with
| Some v -> v :: ends
| None -> ends
in
merge_vertex g to_be_merged
let merge_starts ?(strict=false) ?specified_vertex g =
let accumulator v accu =
if
let in_d = B.G.in_degree g v in
in_d = 0 ||
((not strict) && in_d = List.length (B.G.find_all_edges g v v))
then v :: accu
else accu
in
let starts = B.G.(fold_vertex accumulator g []) in
let to_be_merged =
match specified_vertex with
| Some v -> v :: starts
| None -> starts
in
merge_vertex g to_be_merged
let merge_scc ?(loop_killer=false) ?specified_vertex g =
let module C = Components.Make(B.G) in
let components = C.scc_list g in
let alter accu to_be_identified =
let to_be_identified =
match specified_vertex with
| None -> to_be_identified
| Some f -> (f to_be_identified) :: to_be_identified in
let v = List.hd to_be_identified in
let accu = merge_vertex accu to_be_identified in
if loop_killer
then B.remove_edge accu v v
else accu in
List.fold_left alter g components
end
module P(G: Sig.P) = B(Builder.P(G))
module I(G: Sig.I) = struct
include B(Builder.I(G))
let merge_vertex g vl = ignore (merge_vertex g vl)
let merge_edges_e ?src ?dst g el = ignore (merge_edges_e ?src ?dst g el)
let merge_edges_with_label ?src ?dst ?label g l =
ignore (merge_edges_with_label ?src ?dst ?label g l)
let merge_isolabelled_edges g = ignore (merge_isolabelled_edges g)
let merge_ends ?strict ?specified_vertex g =
ignore (merge_ends ?strict ?specified_vertex g)
let merge_starts ?strict ?specified_vertex g =
ignore (merge_starts ?strict ?specified_vertex g)
let merge_scc ?loop_killer ?specified_vertex g =
ignore (merge_scc ?loop_killer ?specified_vertex g)
end