Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cbe13d77321491e66bf751b5202e7e0288e02eab
[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
165  if ((node_free_function) && (n->data))
166     node_free_function(n->data);
167
168   cursor = 0;
169   xbt_dynar_foreach(g->nodes, cursor, node)
170     {
171       if (node == n)
172         xbt_dynar_cursor_rm(g->nodes, &cursor);
173
174     }
175
176   return;
177 }
178
179 /** @brief remove the given edge from the given graph */
180 void xbt_graph_free_edge(xbt_graph_t g, xbt_edge_t e,
181                          void free_function(void *ptr))
182 {
183   int idx;
184   int cursor = 0;
185   xbt_edge_t edge = NULL; 
186
187   if ((free_function) && (e->data))
188     free_function(e->data);
189
190   xbt_dynar_foreach(g->edges, cursor, edge) 
191     {
192     if (edge == e)
193       {
194         if (g->directed) {
195           idx = __xbt_find_in_dynar(edge->dst->in,edge); 
196           xbt_dynar_remove_at(edge->dst->in, idx,NULL);
197         } else { /* only the out field is used */
198           idx = __xbt_find_in_dynar(edge->dst->out,edge); 
199           xbt_dynar_remove_at(edge->dst->out, idx,NULL);
200         }
201
202         idx = __xbt_find_in_dynar(edge->src->out,edge);
203         xbt_dynar_remove_at(edge->src->out,idx,NULL);   
204
205         xbt_dynar_cursor_rm(g->edges, &cursor); 
206         free(edge);
207         break;
208       }
209     }
210 }
211
212 int __xbt_find_in_dynar(xbt_dynar_t dynar, void *p)
213 {
214
215   int cursor = 0;
216   void *tmp=NULL;
217
218   xbt_dynar_foreach(dynar, cursor, tmp)
219     {
220       if (tmp == p)
221         return cursor;
222     }
223   return -1;
224 }
225
226 /** @brief Retrieve the graph's nodes as a dynar */
227 xbt_dynar_t xbt_graph_get_nodes(xbt_graph_t g)
228 {
229   return g->nodes;
230 }
231
232 /** @brief Retrieve the graph's edges as a dynar */
233 xbt_dynar_t xbt_graph_get_edges(xbt_graph_t g)
234 {
235   return g->edges;
236 }
237
238 /** @brief Retrieve the node at the source of the given edge */
239 xbt_node_t xbt_graph_edge_get_source(xbt_edge_t e)
240 {
241
242   return e->src;
243 }
244
245 /** @brief Retrieve the node being the target of the given edge */
246 xbt_node_t xbt_graph_edge_get_target(xbt_edge_t e)
247 {
248   return e->dst;
249 }
250
251
252 /** @brief Set the weight of the given edge */
253 void xbt_graph_edge_set_length(xbt_edge_t e, double length)
254 {
255   e->length = length;
256
257 }
258
259 double xbt_graph_edge_get_length(xbt_edge_t e)
260 {
261   return e->length;
262 }
263
264
265 /** @brief construct the adjacency matrix corresponding to the given graph
266  * 
267  * The weights are the distances between nodes
268  */
269 double *xbt_graph_get_length_matrix(xbt_graph_t g)
270 {
271   int cursor = 0;
272   int in_cursor = 0;
273   int  idx,i;
274   unsigned long n;
275   xbt_edge_t edge = NULL;
276   xbt_node_t node=NULL;
277   double *d = NULL;
278
279 # define D(u,v) d[(u)*n+(v)]
280   n = xbt_dynar_length(g->nodes);
281
282   d = (double *) xbt_new0(double, n*n);
283
284   for (i = 0; i < n * n; i++)
285     {
286       d[i] = -1.0;
287     }
288  
289   xbt_dynar_foreach(g->nodes, cursor, node) 
290     {
291       in_cursor = 0;
292       D(cursor, cursor) = 0;
293     
294       xbt_dynar_foreach(node->out, in_cursor, edge)
295         {
296           if (edge->dst==node) 
297             idx= __xbt_find_in_dynar(g->nodes, edge->src);
298           else /*case of  undirected graphs*/ 
299              idx = __xbt_find_in_dynar(g->nodes, edge->dst);
300           D( cursor,idx) = edge->length;
301         }
302     }
303
304 # undef D
305
306   return d;
307 }
308
309 /** @brief Floyd-Warshall algorithm for shortest path finding
310  * 
311  * From wikipedia: 
312  * 
313  * The Floyd–Warshall algorithm takes as input an adjacency matrix
314  * representation of a weighted, directed graph (V, E). The weight of a
315  * path between two vertices is the sum of the weights of the edges along
316  * that path. The edges E of the graph may have negative weights, but the
317  * graph must not have any negative weight cycles. The algorithm computes,
318  * for each pair of vertices, the minimum weight among all paths between
319  * the two vertices. The running time complexity is Θ(|V|3).
320  */ 
321 void xbt_floyd_algorithm(xbt_graph_t g, double *adj, double *d,
322                          xbt_node_t * p)
323 {
324   int i, j, k;
325   unsigned long n;
326   n = xbt_dynar_length(g->nodes);
327
328 # define D(u,v) d[(u)*n+(v)]
329 # define P(u,v) p[(u)*n+(v)]
330
331   for (i = 0; i < n * n; i++)
332     {
333       d[i] = adj[i];
334     }
335
336
337   for (i = 0; i < n; i++)
338     {
339       for (j = 0; j < n; j++)
340         {
341           if (D(i, j) != -1)
342             {
343               P(i,j) =*((xbt_node_t*) xbt_dynar_get_ptr(g->nodes, i));       
344             }
345         }
346     }
347  
348   for (k = 0; k < n; k++)
349     {
350       for (i = 0; i < n; i++)
351         {
352           for (j = 0; j < n; j++)
353             {
354               if ((D(i, k) != -1) && (D(k, j) != -1))
355                 {
356                   if ((D(i, j) == -1) || (D(i, j) > D(i, k) + D(k, j)))
357                     {
358                       D(i, j) = D(i, k) + D(k, j);
359                       P(i, j) = P(k, j);
360                     }
361                 }
362             }
363         }
364     }
365
366
367
368 # undef P
369 # undef D
370 }
371
372 /** @brief computes all-pairs shortest paths */
373 xbt_node_t *xbt_graph_shortest_paths(xbt_graph_t g)
374 {
375   xbt_node_t *p;
376   xbt_node_t *r;
377   int i, j, k;
378   unsigned long n;
379
380   double *adj = NULL;
381   double *d = NULL;
382
383 # define P(u,v) p[(u)*n+(v)]
384 # define R(u,v) r[(u)*n+(v)]
385
386   n = xbt_dynar_length(g->nodes);
387   adj = xbt_graph_get_length_matrix(g);
388   d = xbt_new0(double,n*n);
389   p = xbt_new0(xbt_node_t,n*n);
390   r = xbt_new0(xbt_node_t,n*n);
391  
392   xbt_floyd_algorithm(g, adj, d, p);
393  
394   for (i = 0; i < n; i++)
395     {
396       for (j = 0; j < n; j++)
397         {
398           k = j;
399
400           while ((P(i, k)) && (__xbt_find_in_dynar(g->nodes, P(i, k)) != i))
401             {
402               k = __xbt_find_in_dynar(g->nodes, P(i, k));
403             }
404
405           if (P(i, j))
406             {
407               R(i, j) = *((xbt_node_t*) xbt_dynar_get_ptr(g->nodes, k));
408             }
409         }
410     }
411 # undef R
412 # undef P
413
414   free(d);
415   free(p);
416   free(adj);
417   return r;
418 }
419
420 /** @brief Extract a spanning tree of the given graph */
421 xbt_edge_t* xbt_graph_spanning_tree_prim(xbt_graph_t g)
422 {
423   int tree_size=0;
424   int tree_size_max=xbt_dynar_length(g->nodes)-1;
425   xbt_edge_t *tree = xbt_new0(xbt_edge_t,tree_size_max);
426   xbt_edge_t e,edge;
427   xbt_node_t node = NULL;
428   xbt_dynar_t edge_list = NULL;
429   xbt_heap_t heap = xbt_heap_new(10,NULL);
430   int cursor;
431
432   xbt_assert0(!(g->directed),
433               "Spanning trees do not make sense on directed graphs");
434
435   xbt_dynar_foreach(g->nodes, cursor, node) {
436     node->xbtdata = NULL;
437   }
438
439   node = xbt_dynar_getfirst_as(g->nodes,xbt_node_t);
440   node->xbtdata = (void*) 1;
441   edge_list = node->out;
442   xbt_dynar_foreach(edge_list, cursor, e)
443     xbt_heap_push(heap,e, -(e->length));
444   
445   while((edge=xbt_heap_pop(heap))) {
446     if((edge->src->xbtdata) && (edge->dst->xbtdata)) continue;
447     tree[tree_size++]=edge;
448     if(!(edge->src->xbtdata)) {
449       edge->src->xbtdata = (void*) 1;
450       edge_list = edge->src->out;
451       xbt_dynar_foreach(edge_list, cursor, e) {
452         xbt_heap_push(heap,e, -(e->length));
453       }
454     } else {
455       edge->dst->xbtdata = (void*) 1;
456       edge_list = edge->dst->out;
457       xbt_dynar_foreach(edge_list, cursor, e) {
458         xbt_heap_push(heap,e, -(e->length));
459       }
460     }
461     if(tree_size==tree_size_max) break;
462   }
463   
464   xbt_heap_free(heap);
465
466   return tree;
467 }
468
469 /** @brief Topological sort on the given graph 
470  *
471  *  From wikipedia:
472  * 
473  * In graph theory, a topological sort of a directed acyclic graph (DAG) is
474  * a linear ordering of its nodes which is compatible with the partial
475  * order R induced on the nodes where x comes before y (xRy) if there's a
476  * directed path from x to y in the DAG. An equivalent definition is that
477  * each node comes before all nodes to which it has edges. Every DAG has at
478  * least one topological sort, and may have many.
479  */
480 xbt_node_t* xbt_graph_topo_sort(xbt_graph_t g)
481 {
482  
483   xbt_node_t* sorted;
484   int cursor,idx;
485   xbt_node_t node;
486  unsigned long n;
487
488  n= xbt_dynar_length(g->nodes); 
489  idx=n-1;
490
491   sorted=xbt_malloc(n*sizeof(xbt_node_t));
492   xbt_dynar_foreach(g->nodes,cursor , node)
493     {
494       node->xbtdata=xbt_new0(int,1);
495     }
496
497   xbt_dynar_foreach(g->nodes,cursor , node) 
498     { 
499       xbt_graph_depth_visit(g,node,sorted,&idx);   
500     }
501   xbt_dynar_foreach(g->nodes, cursor, node) 
502    {
503     node->xbtdata = NULL;
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