Release coccinelle-0.2.2-rc2
[bpt/coccinelle.git] / commons / ograph_extended.ml
CommitLineData
34e49164
C
1open Common
2
3open Ocollection
4open Oset
5open Oassoc
6(* open Ograph *)
7
8open Oassocb
9open Osetb
10
ae4735db
C
11(*
12 * graph structure:
34e49164
C
13 * - node: index -> nodevalue
14 * - arc: (index * index) * edgevalue
ae4735db
C
15 *
16 * invariant: key in pred is also in succ (completness) and value in
34e49164 17 * either assoc is a key also.
ae4735db 18 *
34e49164 19 * How ? matrix ? but no growing array :(
ae4735db 20 *
34e49164
C
21 * When need index ? Must have an index when can't just use nodevalue
22 * as a key, cos sometimes may have 2 times the same key, but it must
23 * be 2 different nodes. For instance in program f(); f(); we want 2
24 * nodes, one per f(); hence the index. If each node is different,
25 * then no problem, can omit index.
ae4735db 26 *
34e49164 27 * todo?: prend en parametre le type de finitemap et set a prendre
ae4735db 28 * todo?: add_arc doit ramer, car del la key, puis add => better to
34e49164 29 * have a ref to a set.
ae4735db
C
30 *
31 * opti: graph with pointers and a tag visited => need keep global value
34e49164 32 * visited_counter. check(that node is in, ...), display.
ae4735db
C
33 * opti: when the graph structure is stable, have a method compact, that
34 * transforms that in a matrix (assert that all number between 0 and
34e49164 35 * free_index are used, or do some defrag-like-move/renaming).
ae4735db 36 *
34e49164
C
37 *)
38
39type nodei = int
40
41class ['a,'b] ograph_extended =
42 let build_assoc () = new oassocb [] in (* opti?: = oassoch *)
43 let build_set () = new osetb Setb.empty in
44
45 object(o)
46 (* inherit ['a] ograph *)
ae4735db 47
34e49164
C
48 val free_index = 0
49
50 val succ = build_assoc()
51 val pred = build_assoc()
52 val nods = build_assoc()
53
ae4735db 54 method add_node (e: 'a) =
34e49164 55 let i = free_index in
ae4735db
C
56 ({<
57 nods = nods#add (i, e);
34e49164
C
58 pred = pred#add (i, build_set() );
59 succ = succ#add (i, build_set() );
60 free_index = i + 1;
61 >}, i)
62
ae4735db
C
63 method add_nodei i (e: 'a) =
64 ({<
65 nods = nods#add (i, e);
34e49164
C
66 pred = pred#add (i, build_set() );
67 succ = succ#add (i, build_set() );
68 free_index = (max free_index i) + 1;
69 >}, i)
70
71
ae4735db 72 method del_node (i) =
34e49164 73 {<
ae4735db 74 (* check: e is effectively the index associated with e,
34e49164
C
75 and check that already in *)
76
77 (* todo: assert that have no pred and succ, otherwise
ae4735db 78 * will have some dangling pointers
34e49164 79 *)
ae4735db 80 nods = nods#delkey i;
34e49164
C
81 pred = pred#delkey i;
82 succ = succ#delkey i;
83 >}
84
ae4735db 85 method replace_node (i, (e: 'a)) =
34e49164
C
86 assert (nods#haskey i);
87 {<
88 nods = nods#replkey (i, e);
89 >}
90
ae4735db
C
91 method add_arc ((a,b),(v: 'b)) =
92 {<
34e49164
C
93 succ = succ#replkey (a, (succ#find a)#add (b, v));
94 pred = pred#replkey (b, (pred#find b)#add (a, v));
95 >}
96 method del_arc ((a,b),v) =
ae4735db 97 {<
34e49164
C
98 succ = succ#replkey (a, (succ#find a)#del (b,v));
99 pred = pred#replkey (b, (pred#find b)#del (a,v));
100 >}
101
102 method successors e = succ#find e
103 method predecessors e = pred#find e
104
105 method nodes = nods
106 method allsuccessors = succ
107
108(*
ae4735db
C
109 method ancestors xs =
110 let rec aux xs acc =
34e49164
C
111 match xs#view with (* could be done with an iter *)
112 | Empty -> acc
ae4735db 113 | Cons(x, xs) -> (acc#add x)
34e49164
C
114 +> (fun newacc -> aux (o#predecessors x) newacc)
115 +> (fun newacc -> aux xs newacc)
116 in aux xs (f2()) (* (new osetb []) *)
117
ae4735db
C
118 method children xs =
119 let rec aux xs acc =
34e49164
C
120 match xs#view with (* could be done with an iter *)
121 | Empty -> acc
ae4735db 122 | Cons(x, xs) -> (acc#add x)
34e49164
C
123 +> (fun newacc -> aux (o#successors x) newacc)
124 +> (fun newacc -> aux xs newacc)
125 in aux xs (f2()) (* (new osetb []) *)
126
ae4735db 127 method brothers x =
34e49164
C
128 let parents = o#predecessors x in
129 (parents#fold (fun acc e -> acc $++$ o#successors e) (f2()))#del x
130
131*)
132
ae4735db 133 end
34e49164
C
134
135
136
137
138class ['a,'b] ograph_mutable =
139 let build_assoc () = new oassocb [] in
140 let build_set () = new osetb Setb.empty in
141
142 object(o)
ae4735db 143
34e49164
C
144 val mutable free_index = 0
145
146 val mutable succ = build_assoc()
147 val mutable pred = build_assoc()
148 val mutable nods = build_assoc()
149
ae4735db 150 method add_node (e: 'a) =
34e49164 151 let i = free_index in
ae4735db 152 nods <- nods#add (i, e);
34e49164
C
153 pred <- pred#add (i, build_set() );
154 succ <- succ#add (i, build_set() );
155 free_index <- i + 1;
156 i
157
ae4735db
C
158 method add_nodei i (e: 'a) =
159 nods <- nods#add (i, e);
34e49164
C
160 pred <- pred#add (i, build_set() );
161 succ <- succ#add (i, build_set() );
162 free_index <- (max free_index i) + 1;
163
164
ae4735db
C
165 method del_node (i) =
166 (* check: e is effectively the index associated with e,
34e49164
C
167 and check that already in *)
168
169 (* todo: assert that have no pred and succ, otherwise
ae4735db 170 * will have some dangling pointers
34e49164 171 *)
ae4735db 172 nods <- nods#delkey i;
34e49164
C
173 pred <- pred#delkey i;
174 succ <- succ#delkey i;
175
ae4735db 176 method replace_node (i, (e: 'a)) =
34e49164
C
177 assert (nods#haskey i);
178 nods <- nods#replkey (i, e);
ae4735db
C
179
180 method add_arc ((a,b),(v: 'b)) =
34e49164
C
181 succ <- succ#replkey (a, (succ#find a)#add (b, v));
182 pred <- pred#replkey (b, (pred#find b)#add (a, v));
183 method del_arc ((a,b),v) =
184 succ <- succ#replkey (a, (succ#find a)#del (b,v));
185 pred <- pred#replkey (b, (pred#find b)#del (a,v));
186
187 method successors e = succ#find e
188 method predecessors e = pred#find e
189
190 method nodes = nods
191 method allsuccessors = succ
192
ae4735db 193 end
34e49164
C
194
195
196(* depth first search *)
197let dfs_iter xi f g =
198 let already = Hashtbl.create 101 in
ae4735db
C
199 let rec aux_dfs xs =
200 xs +> List.iter (fun xi ->
34e49164
C
201 if Hashtbl.mem already xi then ()
202 else begin
203 Hashtbl.add already xi true;
204 f xi;
205 let succ = g#successors xi in
206 aux_dfs (succ#tolist +> List.map fst);
207 end
208 ) in
209 aux_dfs [xi]
210
211
ae4735db 212let dfs_iter_with_path xi f g =
34e49164 213 let already = Hashtbl.create 101 in
ae4735db 214 let rec aux_dfs path xi =
34e49164
C
215 if Hashtbl.mem already xi then ()
216 else begin
217 Hashtbl.add already xi true;
218 f xi path;
219 let succ = g#successors xi in
220 let succ' = succ#tolist +> List.map fst in
ae4735db 221 succ' +> List.iter (fun yi ->
34e49164
C
222 aux_dfs (xi::path) yi
223 );
224 end
225 in
226 aux_dfs [] xi
ae4735db
C
227
228
34e49164 229
485bce71 230let generate_ograph_generic g label fnode filename =
978fd7e5 231 Common.with_open_outfile filename (fun (pr,_) ->
485bce71
C
232 pr "digraph misc {\n" ;
233 pr "size = \"10,10\";\n" ;
234 (match label with
235 None -> ()
236 | Some x -> pr (Printf.sprintf "label = \"%s\";\n" x));
237
238 let nodes = g#nodes in
ae4735db 239 nodes#iter (fun (k,node) ->
485bce71
C
240 let (str,border_color,inner_color) = fnode (k, node) in
241 let color =
242 match inner_color with
243 None ->
244 (match border_color with
245 None -> ""
246 | Some x -> Printf.sprintf ", style=\"setlinewidth(3)\", color = %s" x)
247 | Some x ->
248 (match border_color with
ae4735db 249 None -> Printf.sprintf ", style=\"setlinewidth(3),filled\", fillcolor = %s" x
485bce71 250 | Some x' -> Printf.sprintf ", style=\"setlinewidth(3),filled\", fillcolor = %s, color = %s" x x') in
ae4735db 251 (* so can see if nodes without arcs were created *)
485bce71
C
252 pr (sprintf "%d [label=\"%s [%d]\"%s];\n" k str k color)
253 );
254
ae4735db 255 nodes#iter (fun (k,node) ->
485bce71
C
256 let succ = g#successors k in
257 succ#iter (fun (j,edge) ->
258 pr (sprintf "%d -> %d;\n" k j);
259 );
260 );
261 pr "}\n" ;
262 );
263 ()
264
34e49164
C
265
266let generate_ograph_xxx g filename =
267 with_open_outfile filename (fun (pr,_) ->
268 pr "digraph misc {\n" ;
269 pr "size = \"10,10\";\n" ;
270
271 let nodes = g#nodes in
ae4735db
C
272 nodes#iter (fun (k,(node, s)) ->
273 (* so can see if nodes without arcs were created *)
485bce71 274 pr (sprintf "%d [label=\"%s [%d]\"];\n" k s k)
34e49164
C
275 );
276
ae4735db 277 nodes#iter (fun (k,node) ->
34e49164
C
278 let succ = g#successors k in
279 succ#iter (fun (j,edge) ->
280 pr (sprintf "%d -> %d;\n" k j);
281 );
282 );
283 pr "}\n" ;
284 );
34e49164
C
285 ()
286
485bce71
C
287
288let launch_gv_cmd filename =
ae4735db 289 let _status =
485bce71 290 Unix.system ("dot " ^ filename ^ " -Tps -o " ^ filename ^ ".ps;") in
34e49164
C
291 let _status = Unix.system ("gv " ^ filename ^ ".ps &")
292 in
293 (* zarb: I need this when I launch the program via eshell, otherwise gv
294 do not get the chance to be launched *)
ae4735db 295 Unix.sleep 1;
34e49164
C
296 ()
297
ae4735db 298let print_ograph_extended g filename launchgv =
34e49164 299 generate_ograph_xxx g filename;
485bce71 300 if launchgv then launch_gv_cmd filename
34e49164 301
ae4735db 302let print_ograph_mutable g filename launchgv =
34e49164 303 generate_ograph_xxx g filename;
485bce71
C
304 if launchgv then launch_gv_cmd filename
305
ae4735db 306let print_ograph_mutable_generic g label fnode ~output_file ~launch_gv =
485bce71
C
307 generate_ograph_generic g label fnode output_file;
308 if launch_gv then launch_gv_cmd output_file