Logo AND Algorithmique Numérique Distribuée

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