Logo AND Algorithmique Numérique Distribuée

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