Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
sanitize logging channel naming
[simgrid.git] / src / xbt / graph.c
1 /*      $Id$     */
2
3 /* a generic graph library.                                                 */
4
5 /* Copyright (c) 2006 Darina Dimitrova, Arnaud Legrand.                     */
6 /* All rights reserved.                                                     */
7
8 /* This program is free software; you can redistribute it and/or modify it
9  * under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include <stdlib.h>
12 #include "xbt/sysdep.h"
13 #include "xbt/log.h"
14 #include "xbt/graph.h"
15 #include "graph_private.h"
16 #include "xbt/graphxml_parse.h"
17 #include "xbt/dict.h"
18 #include "xbt/heap.h"
19
20
21
22
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(graph, xbt, "Graph");
24
25
26
27 /** @brief Constructor
28  *  @return a new graph
29  */
30 xbt_graph_t xbt_graph_new_graph(unsigned short int directed, void *data)
31 {
32   xbt_graph_t graph = NULL;
33   graph = xbt_new0(struct xbt_graph, 1);
34   graph->directed = directed;
35   graph->data = data;
36   graph->nodes = xbt_dynar_new(sizeof(xbt_node_t), NULL);
37   graph->edges = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
38
39   return graph;
40 }
41
42 /** @brief add a node to the given graph */
43 xbt_node_t xbt_graph_new_node(xbt_graph_t g, void *data)
44 {
45   xbt_node_t node = NULL;
46   node = xbt_new0(struct xbt_node, 1);
47   node->data = data;
48   node->in = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
49   node->out = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
50   node->position_x = -1.0;
51   node->position_y = -1.0;
52
53   xbt_dynar_push(g->nodes, &node);
54
55   return node;
56 }
57
58 /** @brief add an edge to the given graph */
59 xbt_edge_t xbt_graph_new_edge(xbt_graph_t g,
60                               xbt_node_t src, xbt_node_t dst, void *data)
61 {
62   xbt_edge_t edge = NULL;
63
64
65   edge = xbt_new0(struct xbt_edge, 1);
66   xbt_dynar_push(src->out, &edge);
67   if (g->directed)
68     xbt_dynar_push(dst->in, &edge);
69   else                          /* only the "out" field is used */
70     xbt_dynar_push(dst->out, &edge);
71
72   edge->data = data;
73   edge->src = src;
74   edge->dst = dst;
75   if (!g->directed) {
76     xbt_dynar_push(src->in, &edge);
77     xbt_dynar_push(dst->out, &edge);
78   }
79
80
81   xbt_dynar_push(g->edges, &edge);
82
83   return edge;
84 }
85
86 void *xbt_graph_node_get_data(xbt_node_t node)
87 {
88   return node->data;
89 }
90
91 void *xbt_graph_edge_get_data(xbt_edge_t edge)
92 {
93   return edge->data;
94 }
95
96 /** @brief Destructor
97  *  @param l: poor victim
98  *
99  * Free the graph structure. 
100  */
101 void xbt_graph_free_graph(xbt_graph_t g,
102                           void node_free_function(void *ptr),
103                           void edge_free_function(void *ptr),
104                           void graph_free_function(void *ptr))
105 {
106   int cursor = 0;
107   xbt_node_t node = NULL;
108   xbt_edge_t edge = NULL;
109
110
111   xbt_dynar_foreach(g->nodes, cursor, node) {
112     xbt_dynar_free(&(node->out));
113     xbt_dynar_free(&(node->in));
114     if (node_free_function)
115       node_free_function(node->data);
116   }
117
118   xbt_dynar_foreach(g->edges, cursor, edge) {
119     if (edge_free_function)
120       edge_free_function(edge->data);
121   }
122
123   xbt_dynar_foreach(g->nodes, cursor, node)
124       free(node);
125   xbt_dynar_free(&(g->nodes));
126
127   xbt_dynar_foreach(g->edges, cursor, edge)
128       free(edge);
129   xbt_dynar_free(&(g->edges));
130
131   free(g);
132
133   return;
134 }
135
136
137 /** @brief remove the given node from the given graph */
138 void xbt_graph_free_node(xbt_graph_t g, xbt_node_t n,
139                          void_f_pvoid_t * node_free_function,
140                          void_f_pvoid_t * edge_free_function)
141 {
142   unsigned long nbr;
143   int i;
144   int cursor = 0;
145   xbt_node_t node = NULL;
146   xbt_edge_t edge = NULL;
147
148   nbr = xbt_dynar_length(g->edges);
149   cursor = 0;
150   for (i = 0; i < nbr; i++) {
151     xbt_dynar_cursor_get(g->edges, &cursor, &edge);
152
153     if ((edge->dst == n) || (edge->src == n)) {
154       xbt_graph_free_edge(g, edge, edge_free_function);
155     } else
156       xbt_dynar_cursor_step(g->edges, &cursor);
157   }
158
159   if ((node_free_function) && (n->data))
160     node_free_function(n->data);
161
162   cursor = 0;
163   xbt_dynar_foreach(g->nodes, cursor, node)
164     if (node == n)
165       xbt_dynar_cursor_rm(g->nodes, &cursor);
166
167   xbt_dynar_free(&(n->in));
168   xbt_dynar_free(&(n->out));
169
170   free(n);
171
172   return;
173 }
174
175 /** @brief remove the given edge from the given graph */
176 void xbt_graph_free_edge(xbt_graph_t g, xbt_edge_t e,
177                          void free_function(void *ptr))
178 {
179   int idx;
180   int cursor = 0;
181   xbt_edge_t edge = NULL;
182
183   if ((free_function) && (e->data))
184     free_function(e->data);
185
186   xbt_dynar_foreach(g->edges, cursor, edge) {
187     if (edge == e) {
188       if (g->directed) {
189         idx = __xbt_find_in_dynar(edge->dst->in, edge);
190         xbt_dynar_remove_at(edge->dst->in, idx, NULL);
191       } else {                  /* only the out field is used */
192         idx = __xbt_find_in_dynar(edge->dst->out, edge);
193         xbt_dynar_remove_at(edge->dst->out, idx, NULL);
194       }
195
196       idx = __xbt_find_in_dynar(edge->src->out, edge);
197       xbt_dynar_remove_at(edge->src->out, idx, NULL);
198
199       xbt_dynar_cursor_rm(g->edges, &cursor);
200       free(edge);
201       break;
202     }
203   }
204 }
205
206 int __xbt_find_in_dynar(xbt_dynar_t dynar, void *p)
207 {
208
209   int cursor = 0;
210   void *tmp = NULL;
211
212   xbt_dynar_foreach(dynar, cursor, tmp) {
213     if (tmp == p)
214       return cursor;
215   }
216   return -1;
217 }
218
219 /** @brief Retrieve the graph's nodes as a dynar */
220 xbt_dynar_t xbt_graph_get_nodes(xbt_graph_t g)
221 {
222   return g->nodes;
223 }
224
225 /** @brief Retrieve the graph's edges as a dynar */
226 xbt_dynar_t xbt_graph_get_edges(xbt_graph_t g)
227 {
228   return g->edges;
229 }
230
231 /** @brief Retrieve the node at the source of the given edge */
232 xbt_node_t xbt_graph_edge_get_source(xbt_edge_t e)
233 {
234
235   return e->src;
236 }
237
238 /** @brief Retrieve the node being the target of the given edge */
239 xbt_node_t xbt_graph_edge_get_target(xbt_edge_t e)
240 {
241   return e->dst;
242 }
243
244
245 /** @brief Set the weight of the given edge */
246 void xbt_graph_edge_set_length(xbt_edge_t e, double length)
247 {
248   e->length = length;
249
250 }
251
252 double xbt_graph_edge_get_length(xbt_edge_t e)
253 {
254   return e->length;
255 }
256
257
258 /** @brief construct the adjacency matrix corresponding to the given graph
259  * 
260  * The weights are the distances between nodes
261  */
262 double *xbt_graph_get_length_matrix(xbt_graph_t g)
263 {
264   int cursor = 0;
265   int in_cursor = 0;
266   int idx, i;
267   unsigned long n;
268   xbt_edge_t edge = NULL;
269   xbt_node_t node = NULL;
270   double *d = NULL;
271
272 # define D(u,v) d[(u)*n+(v)]
273   n = xbt_dynar_length(g->nodes);
274
275   d = (double *) xbt_new0(double, n * n);
276
277   for (i = 0; i < n * n; i++) {
278     d[i] = -1.0;
279   }
280
281   xbt_dynar_foreach(g->nodes, cursor, node) {
282     in_cursor = 0;
283     D(cursor, cursor) = 0;
284
285     xbt_dynar_foreach(node->out, in_cursor, edge) {
286       if (edge->dst == node)
287         idx = __xbt_find_in_dynar(g->nodes, edge->src);
288       else                      /*case of  undirected graphs */
289         idx = __xbt_find_in_dynar(g->nodes, edge->dst);
290       D(cursor, idx) = edge->length;
291     }
292   }
293
294 # undef D
295
296   return d;
297 }
298
299 /** @brief Floyd-Warshall algorithm for shortest path finding
300  * 
301  * From wikipedia: 
302  * 
303  * The Floyd–Warshall algorithm takes as input an adjacency matrix
304  * representation of a weighted, directed graph (V, E). The weight of a
305  * path between two vertices is the sum of the weights of the edges along
306  * that path. The edges E of the graph may have negative weights, but the
307  * graph must not have any negative weight cycles. The algorithm computes,
308  * for each pair of vertices, the minimum weight among all paths between
309  * the two vertices. The running time complexity is Θ(|V|3).
310  */
311 void xbt_floyd_algorithm(xbt_graph_t g, double *adj, double *d,
312                          xbt_node_t * p)
313 {
314   int i, j, k;
315   unsigned long n;
316   n = xbt_dynar_length(g->nodes);
317
318 # define D(u,v) d[(u)*n+(v)]
319 # define P(u,v) p[(u)*n+(v)]
320
321   for (i = 0; i < n * n; i++) {
322     d[i] = adj[i];
323   }
324
325
326   for (i = 0; i < n; i++) {
327     for (j = 0; j < n; j++) {
328       if (D(i, j) != -1) {
329         P(i, j) = *((xbt_node_t *) xbt_dynar_get_ptr(g->nodes, i));
330       }
331     }
332   }
333
334   for (k = 0; k < n; k++) {
335     for (i = 0; i < n; i++) {
336       for (j = 0; j < n; j++) {
337         if ((D(i, k) != -1) && (D(k, j) != -1)) {
338           if ((D(i, j) == -1) || (D(i, j) > D(i, k) + D(k, j))) {
339             D(i, j) = D(i, k) + D(k, j);
340             P(i, j) = P(k, j);
341           }
342         }
343       }
344     }
345   }
346
347
348
349 # undef P
350 # undef D
351 }
352
353 /** @brief computes all-pairs shortest paths */
354 xbt_node_t *xbt_graph_shortest_paths(xbt_graph_t g)
355 {
356   xbt_node_t *p;
357   xbt_node_t *r;
358   int i, j, k;
359   unsigned long n;
360
361   double *adj = NULL;
362   double *d = NULL;
363
364 # define P(u,v) p[(u)*n+(v)]
365 # define R(u,v) r[(u)*n+(v)]
366
367   n = xbt_dynar_length(g->nodes);
368   adj = xbt_graph_get_length_matrix(g);
369   d = xbt_new0(double, n * n);
370   p = xbt_new0(xbt_node_t, n * n);
371   r = xbt_new0(xbt_node_t, n * n);
372
373   xbt_floyd_algorithm(g, adj, d, p);
374
375   for (i = 0; i < n; i++) {
376     for (j = 0; j < n; j++) {
377       k = j;
378
379       while ((P(i, k)) && (__xbt_find_in_dynar(g->nodes, P(i, k)) != i)) {
380         k = __xbt_find_in_dynar(g->nodes, P(i, k));
381       }
382
383       if (P(i, j)) {
384         R(i, j) = *((xbt_node_t *) xbt_dynar_get_ptr(g->nodes, k));
385       }
386     }
387   }
388 # undef R
389 # undef P
390
391   free(d);
392   free(p);
393   free(adj);
394   return r;
395 }
396
397 /** @brief Extract a spanning tree of the given graph */
398 xbt_edge_t *xbt_graph_spanning_tree_prim(xbt_graph_t g)
399 {
400   int tree_size = 0;
401   int tree_size_max = xbt_dynar_length(g->nodes) - 1;
402   xbt_edge_t *tree = xbt_new0(xbt_edge_t, tree_size_max);
403   xbt_edge_t e, edge;
404   xbt_node_t node = NULL;
405   xbt_dynar_t edge_list = NULL;
406   xbt_heap_t heap = xbt_heap_new(10, NULL);
407   int cursor;
408
409   xbt_assert0(!(g->directed),
410               "Spanning trees do not make sense on directed graphs");
411
412   xbt_dynar_foreach(g->nodes, cursor, node) {
413     node->xbtdata = NULL;
414   }
415
416   node = xbt_dynar_getfirst_as(g->nodes, xbt_node_t);
417   node->xbtdata = (void *) 1;
418   edge_list = node->out;
419   xbt_dynar_foreach(edge_list, cursor, e)
420       xbt_heap_push(heap, e, -(e->length));
421
422   while ((edge = xbt_heap_pop(heap))) {
423     if ((edge->src->xbtdata) && (edge->dst->xbtdata))
424       continue;
425     tree[tree_size++] = edge;
426     if (!(edge->src->xbtdata)) {
427       edge->src->xbtdata = (void *) 1;
428       edge_list = edge->src->out;
429       xbt_dynar_foreach(edge_list, cursor, e) {
430         xbt_heap_push(heap, e, -(e->length));
431       }
432     } else {
433       edge->dst->xbtdata = (void *) 1;
434       edge_list = edge->dst->out;
435       xbt_dynar_foreach(edge_list, cursor, e) {
436         xbt_heap_push(heap, e, -(e->length));
437       }
438     }
439     if (tree_size == tree_size_max)
440       break;
441   }
442
443   xbt_heap_free(heap);
444
445   return tree;
446 }
447
448 /** @brief Topological sort on the given graph 
449  *
450  *  From wikipedia:
451  * 
452  * In graph theory, a topological sort of a directed acyclic graph (DAG) is
453  * a linear ordering of its nodes which is compatible with the partial
454  * order R induced on the nodes where x comes before y (xRy) if there's a
455  * directed path from x to y in the DAG. An equivalent definition is that
456  * each node comes before all nodes to which it has edges. Every DAG has at
457  * least one topological sort, and may have many.
458  */
459 xbt_node_t *xbt_graph_topo_sort(xbt_graph_t g)
460 {
461
462   xbt_node_t *sorted;
463   int cursor, idx;
464   xbt_node_t node;
465   unsigned long n;
466
467   n = xbt_dynar_length(g->nodes);
468   idx = n - 1;
469
470   sorted = xbt_malloc(n * sizeof(xbt_node_t));
471
472   xbt_dynar_foreach(g->nodes, cursor, node)
473     node->xbtdata = xbt_new0(int, 1);
474
475   xbt_dynar_foreach(g->nodes, cursor, node)
476     xbt_graph_depth_visit(g, node, sorted, &idx);
477
478   xbt_dynar_foreach(g->nodes, cursor, node) {
479     free(node->xbtdata);
480     node->xbtdata = NULL;
481   }
482
483   return sorted;
484 }
485
486 /** @brief First-depth graph traversal */
487 void xbt_graph_depth_visit(xbt_graph_t g, xbt_node_t n,
488                            xbt_node_t * sorted, int *idx)
489 {
490   int cursor;
491   xbt_edge_t edge;
492
493   if (*((int *) (n->xbtdata)) == ALREADY_EXPLORED)
494     return;
495   else if (*((int *) (n->xbtdata)) == CURRENTLY_EXPLORING)
496     THROW0(0, 0, "There is a cycle");
497   else {
498     *((int *) (n->xbtdata)) = CURRENTLY_EXPLORING;
499
500     xbt_dynar_foreach(n->out, cursor, edge) {
501       xbt_graph_depth_visit(g, edge->dst, sorted, idx);
502     }
503
504     *((int *) (n->xbtdata)) = ALREADY_EXPLORED;
505     sorted[(*idx)--] = n;
506   }
507 }
508
509 /********************* Import and Export ******************/
510 static xbt_graph_t parsed_graph = NULL;
511 static xbt_dict_t parsed_nodes = NULL;
512
513 static void *(*__parse_node_label_and_data) (xbt_node_t, const char *,
514                                              const char *) = NULL;
515 static void *(*__parse_edge_label_and_data) (xbt_edge_t, const char *,
516                                              const char *) = NULL;
517
518 static void __parse_graph_begin(void)
519 {
520   DEBUG0("<graph>");
521   if (A_graphxml_graph_isDirected == A_graphxml_graph_isDirected_true)
522     parsed_graph = xbt_graph_new_graph(1, NULL);
523   else
524     parsed_graph = xbt_graph_new_graph(0, NULL);
525
526   parsed_nodes = xbt_dict_new();
527 }
528
529 static void __parse_graph_end(void)
530 {
531   xbt_dict_free(&parsed_nodes);
532   DEBUG0("</graph>");
533 }
534
535 static void __parse_node(void)
536 {
537   xbt_node_t node = xbt_graph_new_node(parsed_graph, NULL);
538
539   DEBUG1("<node name=\"%s\"/>", A_graphxml_node_name);
540   if (__parse_node_label_and_data)
541     node->data = __parse_node_label_and_data(node, A_graphxml_node_label,
542                                              A_graphxml_node_data);
543   xbt_graph_parse_get_double(&(node->position_x),
544                              A_graphxml_node_position_x);
545   xbt_graph_parse_get_double(&(node->position_y),
546                              A_graphxml_node_position_y);
547
548   xbt_dict_set(parsed_nodes, A_graphxml_node_name, (void *) node, NULL);
549 }
550
551 static void __parse_edge(void)
552 {
553   xbt_edge_t edge = xbt_graph_new_edge(parsed_graph,
554                                        xbt_dict_get(parsed_nodes,
555                                                     A_graphxml_edge_source),
556                                        xbt_dict_get(parsed_nodes,
557                                                     A_graphxml_edge_target),
558                                        NULL);
559
560   if (__parse_edge_label_and_data)
561     edge->data = __parse_edge_label_and_data(edge, A_graphxml_edge_label,
562                                              A_graphxml_edge_data);
563
564   xbt_graph_parse_get_double(&(edge->length), A_graphxml_edge_length);
565
566   DEBUG3("<edge  source=\"%s\" target=\"%s\" length=\"%f\"/>",
567          (char *) (edge->src)->data,
568          (char *) (edge->dst)->data, xbt_graph_edge_get_length(edge));
569 }
570
571 /** @brief Import a graph from a file following the GraphXML format */
572 xbt_graph_t xbt_graph_read(const char *filename,
573                            void *(node_label_and_data) (xbt_node_t,
574                                                         const char *,
575                                                         const char *),
576                            void *(edge_label_and_data) (xbt_edge_t,
577                                                         const char *,
578                                                         const char *))
579 {
580
581   xbt_graph_t graph = NULL;
582
583   __parse_node_label_and_data = node_label_and_data;
584   __parse_edge_label_and_data = edge_label_and_data;
585
586   xbt_graph_parse_reset_parser();
587
588   STag_graphxml_graph_fun = __parse_graph_begin;
589   ETag_graphxml_graph_fun = __parse_graph_end;
590   ETag_graphxml_node_fun = __parse_node;
591   ETag_graphxml_edge_fun = __parse_edge;
592
593   xbt_graph_parse_open(filename);
594   xbt_assert1((!xbt_graph_parse()), "Parse error in %s", filename);
595   xbt_graph_parse_close();
596
597   graph = parsed_graph;
598   parsed_graph = NULL;
599
600   return graph;
601 }
602
603 /** @brief Export the given graph in the GraphViz formatting for visualization */
604 void xbt_graph_export_graphviz(xbt_graph_t g, const char *filename,
605                                const char *(node_name) (xbt_node_t),
606                                const char *(edge_name) (xbt_edge_t))
607 {
608   int cursor = 0;
609   xbt_node_t node = NULL;
610   xbt_edge_t edge = NULL;
611   FILE *file = NULL;
612   const char *name = NULL;
613
614   file = fopen(filename, "w");
615   xbt_assert1(file, "Failed to open %s \n", filename);
616
617   if (g->directed)
618     fprintf(file, "digraph test {\n");
619   else
620     fprintf(file, "graph test {\n");
621
622   fprintf(file, "  graph [overlap=scale]\n");
623
624   fprintf(file, "  node [shape=box, style=filled]\n");
625   fprintf(file,
626           "  node [width=.3, height=.3, style=filled, color=skyblue]\n\n");
627
628   xbt_dynar_foreach(g->nodes, cursor, node) {
629     fprintf(file, "  \"%p\" ", node);
630     if ((node_name) && ((name = node_name(node))))
631       fprintf(file, "[label=\"%s\"]", name);
632     fprintf(file, ";\n");
633   }
634   xbt_dynar_foreach(g->edges, cursor, edge) {
635     if (g->directed)
636       fprintf(file, "  \"%p\" -> \"%p\"", edge->src, edge->dst);
637     else
638       fprintf(file, "  \"%p\" -- \"%p\"", edge->src, edge->dst);
639     if ((edge_name) && ((name = edge_name(edge))))
640       fprintf(file, "[label=\"%s\"]", name);
641     fprintf(file, ";\n");
642   }
643   fprintf(file, "}\n");
644   fclose(file);
645 }
646
647 /** @brief Export the given graph in the GraphXML format */
648 void xbt_graph_export_graphxml(xbt_graph_t g, const char *filename,
649                                const char *(node_name) (xbt_node_t),
650                                const char *(edge_name) (xbt_edge_t),
651                                const char *(node_data_print) (void *),
652                                const char *(edge_data_print) (void *))
653 {
654   int cursor = 0;
655   xbt_node_t node = NULL;
656   xbt_edge_t edge = NULL;
657   FILE *file = NULL;
658   const char *name = NULL;
659
660   file = fopen(filename, "w");
661   xbt_assert1(file, "Failed to open %s \n", filename);
662
663   fprintf(file, "<?xml version='1.0'?>\n");
664   fprintf(file, "<!DOCTYPE graph SYSTEM \"graphxml.dtd\">\n");
665   if (g->directed)
666     fprintf(file, "<graph isDirected=\"true\">\n");
667   else
668     fprintf(file, "<graph isDirected=\"false\">\n");
669   xbt_dynar_foreach(g->nodes, cursor, node) {
670     fprintf(file, "  <node name=\"%p\" ", node);
671     if ((node_name) && ((name = node_name(node))))
672       fprintf(file, "label=\"%s\" ", name);
673     if ((node_data_print) && ((name = node_data_print(node->data))))
674       fprintf(file, "data=\"%s\" ", name);
675     fprintf(file, ">\n");
676   }
677   xbt_dynar_foreach(g->edges, cursor, edge) {
678     fprintf(file, "  <edge source=\"%p\" target =\"%p\" ",
679             edge->src, edge->dst);
680     if ((edge_name) && ((name = edge_name(edge))))
681       fprintf(file, "label=\"%s\" ", name);
682     if (edge->length >= 0.0)
683       fprintf(file, "length=\"%g\" ", edge->length);
684     if ((edge_data_print) && ((name = edge_data_print(edge->data))))
685       fprintf(file, "data=\"%s\" ", name);
686     fprintf(file, ">\n");
687   }
688   fprintf(file, "</graph>\n");
689   fclose(file);
690 }