Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Move code in simgrid::mc
[simgrid.git] / src / xbt / graph.c
1 /* a generic graph library.                                                 */
2
3 /* Copyright (c) 2006-2014. The SimGrid Team.
4  * All rights reserved.                                                     */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "xbt/graph.h"
12 #include "graph_private.h"
13 #include "xbt/dict.h"
14 #include "xbt/heap.h"
15 #include "xbt/str.h"
16 #include "xbt/file.h"
17
18 #include <errno.h>
19 #include <stdlib.h>
20
21
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_graph, xbt, "Graph");
23
24
25
26 /** @brief Constructor
27  *  @return a new graph
28  */
29 xbt_graph_t xbt_graph_new_graph(unsigned short int directed, void *data)
30 {
31   xbt_graph_t graph = NULL;
32   graph = xbt_new0(struct xbt_graph, 1);
33   graph->directed = directed;
34   graph->data = data;
35   graph->nodes = xbt_dynar_new(sizeof(xbt_node_t), NULL);
36   graph->edges = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
37
38   return graph;
39 }
40
41 /** @brief add a node to the given graph */
42 xbt_node_t xbt_graph_new_node(xbt_graph_t g, void *data)
43 {
44   xbt_node_t node = NULL;
45   node = xbt_new0(struct xbt_node, 1);
46   node->data = data;
47   if (g->directed)
48     /* only the "out" field is used */
49     node->in = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
50
51   node->out = xbt_dynar_new(sizeof(xbt_edge_t), NULL);
52   node->position_x = -1.0;
53   node->position_y = -1.0;
54
55   xbt_dynar_push(g->nodes, &node);
56
57   return node;
58 }
59
60 /** @brief add an edge to the given graph */
61 xbt_edge_t xbt_graph_new_edge(xbt_graph_t g, xbt_node_t src, xbt_node_t dst, void *data)
62 {
63   xbt_edge_t edge = NULL;
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
76   xbt_dynar_push(g->edges, &edge);
77
78   return edge;
79 }
80
81 /** @brief Get the edge connecting src and dst */
82 xbt_edge_t xbt_graph_get_edge(xbt_graph_t g, xbt_node_t src, xbt_node_t dst)
83 {
84   xbt_edge_t edge;
85   unsigned int cursor;
86
87   xbt_dynar_foreach(src->out, cursor, edge) {
88     XBT_DEBUG("%p = %p--%p", edge, edge->src, edge->dst);
89     if ((edge->src == src) && (edge->dst == dst))
90       return edge;
91   }
92   if (!g->directed) {
93     xbt_dynar_foreach(src->out, cursor, edge) {
94       XBT_DEBUG("%p = %p--%p", edge, edge->src, edge->dst);
95       if ((edge->dst == src) && (edge->src == dst))
96         return edge;
97     }
98   }
99   return NULL;
100 }
101
102 /** @brief Get the user data associated to a node */
103 void *xbt_graph_node_get_data(xbt_node_t node)
104 {
105   return node->data;
106 }
107
108 /** @brief Set the user data associated to a node */
109 void xbt_graph_node_set_data(xbt_node_t node, void *data)
110 {
111   node->data = data;
112 }
113
114 /** @brief Get the user data associated to a edge */
115 void *xbt_graph_edge_get_data(xbt_edge_t edge)
116 {
117   return edge->data;
118 }
119
120 /** @brief Set the user data associated to a edge */
121 void xbt_graph_edge_set_data(xbt_edge_t edge, void *data)
122 {
123   edge->data = data;
124 }
125
126 /** @brief Destructor
127  *  @param g: poor victim
128  *  @param node_free_function: function to use to free data associated to each node
129  *  @param edge_free_function: function to use to free data associated to each edge
130  *  @param graph_free_function: function to use to free data associated to g
131  *
132  * Free the graph structure.
133  */
134 void xbt_graph_free_graph(xbt_graph_t g,
135                           void_f_pvoid_t node_free_function,
136                           void_f_pvoid_t edge_free_function,
137                           void_f_pvoid_t graph_free_function)
138 {
139   unsigned int cursor;
140   xbt_node_t node;
141   xbt_edge_t edge;
142
143   xbt_dynar_foreach(g->edges, cursor, edge) {
144     if (edge_free_function)
145       edge_free_function(edge->data);
146     free(edge);
147   }
148   xbt_dynar_free(&(g->edges));
149
150   xbt_dynar_foreach(g->nodes, cursor, node) {
151     xbt_dynar_free(&(node->out));
152     xbt_dynar_free(&(node->in));
153     if (node_free_function)
154       node_free_function(node->data);
155     free(node);
156   }
157   xbt_dynar_free(&(g->nodes));
158
159   if (graph_free_function)
160     graph_free_function(g->data);
161   free(g);
162 }
163
164
165 /** @brief Retrieve the graph's nodes as a dynar */
166 xbt_dynar_t xbt_graph_get_nodes(xbt_graph_t g)
167 {
168   return g->nodes;
169 }
170
171 /** @brief Retrieve the graph's edges as a dynar */
172 xbt_dynar_t xbt_graph_get_edges(xbt_graph_t g)
173 {
174   return g->edges;
175 }
176
177 /** @brief Retrieve the node at the source of the given edge */
178 xbt_node_t xbt_graph_edge_get_source(xbt_edge_t e)
179 {
180   return e->src;
181 }
182
183 /** @brief Retrieve the node being the target of the given edge */
184 xbt_node_t xbt_graph_edge_get_target(xbt_edge_t e)
185 {
186   return e->dst;
187 }
188
189 /** @brief Retrieve the outgoing edges of the given node */
190 xbt_dynar_t xbt_graph_node_get_outedges(xbt_node_t n)
191 {
192   return n->out;
193 }
194
195 /** @brief Set the weight of the given edge */
196 void xbt_graph_edge_set_length(xbt_edge_t e, double length)
197 {
198   e->length = length;
199
200 }
201
202 /** @brief Get the length of a edge */
203 double xbt_graph_edge_get_length(xbt_edge_t edge)
204 {
205   return edge->length;
206 }
207
208 /** @brief Floyd-Warshall algorithm for shortest path finding
209  *
210  * From wikipedia:
211  *
212  * The Floyd–Warshall algorithm takes as input an adjacency matrix
213  * representation of a weighted, directed graph (V, E). The weight of a
214  * path between two vertices is the sum of the weights of the edges along
215  * that path. The edges E of the graph may have negative weights, but the
216  * graph must not have any negative weight cycles. The algorithm computes,
217  * for each pair of vertices, the minimum weight among all paths between
218  * the two vertices. The running time complexity is Θ(|V|3).
219  */
220 void xbt_floyd_algorithm(xbt_graph_t g, double *adj, double *d,
221                          xbt_node_t * p)
222 {
223   unsigned long i, j, k;
224   unsigned long n;
225   n = xbt_dynar_length(g->nodes);
226
227 # define D(u,v) d[(u)*n+(v)]
228 # define P(u,v) p[(u)*n+(v)]
229
230   for (i = 0; i < n * n; i++) {
231     d[i] = adj[i];
232   }
233
234
235   for (i = 0; i < n; i++) {
236     for (j = 0; j < n; j++) {
237       if (D(i, j) != -1) {
238         P(i, j) = *((xbt_node_t *) xbt_dynar_get_ptr(g->nodes, i));
239       }
240     }
241   }
242
243   for (k = 0; k < n; k++) {
244     for (i = 0; i < n; i++) {
245       for (j = 0; j < n; j++) {
246         if ((D(i, k) != -1) && (D(k, j) != -1)) {
247           if ((D(i, j) == -1) || (D(i, j) > D(i, k) + D(k, j))) {
248             D(i, j) = D(i, k) + D(k, j);
249             P(i, j) = P(k, j);
250           }
251         }
252       }
253     }
254   }
255 # undef P
256 # undef D
257 }
258
259 /** @brief Export the given graph in the GraphViz formatting for visualization */
260 void xbt_graph_export_graphviz(xbt_graph_t g, const char *filename,
261                                const char *(node_name) (xbt_node_t),
262                                const char *(edge_name) (xbt_edge_t))
263 {
264   unsigned int cursor = 0;
265   xbt_node_t node = NULL;
266   xbt_edge_t edge = NULL;
267   FILE *file = NULL;
268   const char *name = NULL;
269
270   file = fopen(filename, "w");
271   xbt_assert(file, "Failed to open %s \n", filename);
272
273   if (g->directed)
274     fprintf(file, "digraph test {\n");
275   else
276     fprintf(file, "graph test {\n");
277
278   fprintf(file, "  graph [overlap=scale]\n");
279
280   fprintf(file, "  node [shape=box, style=filled]\n");
281   fprintf(file,
282           "  node [width=.3, height=.3, style=filled, color=skyblue]\n\n");
283
284   xbt_dynar_foreach(g->nodes, cursor, node) {
285     if (node_name){
286       fprintf(file, "  \"%s\";\n", node_name(node));
287     }else{
288       fprintf(file, "  \"%p\";\n", node);
289     }
290   }
291   xbt_dynar_foreach(g->edges, cursor, edge) {
292     const char *c;
293     const char *c_dir = "->";
294     const char *c_ndir = "--";
295     if (g->directed){
296       c = c_dir;
297     }else{
298       c = c_ndir;
299     }
300     const char *src_name, *dst_name;
301     if (node_name){
302       src_name = node_name(edge->src);
303       dst_name = node_name(edge->dst);
304       fprintf(file, "  \"%s\" %s \"%s\"", src_name, c, dst_name);
305     }else{
306       fprintf(file, "  \"%p\" %s \"%p\"", edge->src, c, edge->dst);
307     }
308
309     if ((edge_name) && ((name = edge_name(edge))))
310       fprintf(file, "[label=\"%s\"]", name);
311     fprintf(file, ";\n");
312   }
313   fprintf(file, "}\n");
314   fclose(file);
315 }