Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
dijkstra.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include "config.h"
17
18#include <stdbool.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <math.h>
22#include <cgraph/cgraph.h>
23#include <cgraph/ingraphs.h>
24#include <getopt.h>
25#include <util/alloc.h>
26#include <util/exit.h>
27#include <util/unreachable.h>
28
29static char *CmdName;
30static char **Files;
31static char **Nodes;
32static bool setall; /* if false, don't set dist attribute for
33 * nodes in different components.
34 */
35static bool doPath; /* if true, record shortest paths */
36static bool doDirected; /* if true, use directed paths */
38
39typedef struct {
41 double dist; /* always positive for scanned nodes */
43 bool done;
45
46static double getlength(Agedge_t * e)
47{
48 double len;
49 char* lens;
50 char* p;
51
52 if (len_sym && (*(lens = agxget(e, len_sym)))) {
53 len = strtod (lens, &p);
54 if (len < 0 || p == lens)
55 len = 1;
56 }
57 else
58 len = 1;
59 return len;
60}
61
62static double getdist(Agnode_t * n)
63{
65 data = (nodedata_t *) (n->base.data);
66 return data->dist;
67}
68
69static void setdist(Agnode_t * n, double dist)
70{
72 data = (nodedata_t *) (n->base.data);
73 data->dist = dist;
74}
75
76#define getprev(n) (((nodedata_t*)((n)->base.data))->prev)
77#define setprev(n,p) (((nodedata_t*)((n)->base.data))->prev = (p))
78#define isDone(n) (((nodedata_t*)((n)->base.data))->done)
79#define setDone(n) (((nodedata_t*)((n)->base.data))->done = true)
80
81static int cmpf(void *key1, void *key2) {
82 const double dist1 = getdist(key1);
83 const double dist2 = getdist(key2);
84 if (dist1 < dist2)
85 return -1;
86 if (dist1 > dist2)
87 return 1;
88 if (key1 < key2)
89 return -1;
90 if (key1 > key2)
91 return 1;
92 return 0;
93}
94
95static Dtdisc_t MyDisc = {
96 0, /* int key */
97 0, /* int size */
98 -1, /* int link */
99 0, /* Dtmake_f makef */
100 0, /* Dtfree_f freef */
101 cmpf, /* Dtcompar_f comparf */
102};
103
105{
106 Agnode_t *rv;
107 rv = dtfirst(Q);
108 dtdelete(Q, rv);
109 return rv;
110}
111
112static void update(Dict_t * Q, Agnode_t * dest, Agnode_t * src, double len)
113{
114 double newlen = getdist(src) + len;
115 double oldlen = getdist(dest);
116
117 if (oldlen == 0) { /* first time to see dest */
118 setdist(dest, newlen);
119 if (doPath) setprev(dest, src);
120 dtinsert(Q, dest);
121 } else if (newlen < oldlen) {
122 dtdelete(Q, dest);
123 setdist(dest, newlen);
124 if (doPath) setprev(dest, src);
125 dtinsert(Q, dest);
126 }
127}
128
129static void pre(Agraph_t * g)
130{
131 len_sym = agattr(g, AGEDGE, "len", NULL);
132 aginit(g, AGNODE, "dijkstra", sizeof(nodedata_t), true);
133}
134
135static void post(Agraph_t * g)
136{
137 Agnode_t *v;
138 Agnode_t *prev;
139 char buf[256];
140 char dflt[256];
141 Agsym_t *sym;
142 Agsym_t *psym = NULL;
143 double dist, oldmax;
144 double maxdist = 0.0; /* maximum "finite" distance */
145
146 sym = agattr(g, AGNODE, "dist", "");
147 if (doPath)
148 psym = agattr(g, AGNODE, "prev", "");
149
150 if (setall)
151 snprintf(dflt, sizeof(dflt), "%.3lf", HUGE_VAL);
152
153 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
154 dist = getdist(v);
155 if (dist) {
156 dist--;
157 snprintf(buf, sizeof(buf), "%.3lf", dist);
158 agxset(v, sym, buf);
159 if (doPath && (prev = getprev(v)))
160 agxset(v, psym, agnameof(prev));
161 if (maxdist < dist)
162 maxdist = dist;
163 } else if (setall)
164 agxset(v, sym, dflt);
165 }
166
167 sym = agattrsym(g, "maxdist");
168 if (sym) {
169 if (!setall) {
170 /* if we are preserving distances in other components,
171 * check previous value of maxdist.
172 */
173 oldmax = atof(agxget(g, sym));
174 if (oldmax > maxdist)
175 maxdist = oldmax;
176 }
177 snprintf(buf, sizeof(buf), "%.3lf", maxdist);
178 agxset(g, sym, buf);
179 } else {
180 snprintf(buf, sizeof(buf), "%.3lf", maxdist);
181 agattr(g, AGRAPH, "maxdist", buf);
182 }
183
184 agclean(g, AGNODE, "dijkstra");
185 agclean(g, AGEDGE, "dijkstra");
186}
187
188static void dijkstra(Dict_t * Q, Agraph_t * G, Agnode_t * n)
189{
190 Agnode_t *u;
191 Agedge_t *e;
192
193 pre(G);
194 setdist(n, 1);
195 dtinsert(Q, n);
196 if (doDirected) {
197 while ((u = extract_min(Q))) {
198 setDone (u);
199 for (e = agfstout(G, u); e; e = agnxtout(G, e)) {
200 if (!isDone(e->node)) update(Q, e->node, u, getlength(e));
201 }
202 }
203 } else {
204 while ((u = extract_min(Q))) {
205 setDone (u);
206 for (e = agfstedge(G, u); e; e = agnxtedge(G, e, u)) {
207 if (!isDone(e->node)) update(Q, e->node, u, getlength(e));
208 }
209 }
210 }
211 post(G);
212}
213
214static char *useString =
215 "Usage: dijkstra [-ap?] <node> [<file> <node> <file>]\n\
216 -a - for nodes in a different component, set dist very large\n\
217 -d - use forward directed edges\n\
218 -p - attach shortest path info\n\
219 -? - print usage\n\
220If no files are specified, stdin is used\n";
221
222static void usage(int v)
223{
224 printf("%s",useString);
225 graphviz_exit(v);
226}
227
228static void init(int argc, char *argv[])
229{
230 int i, j, c;
231
232 CmdName = argv[0];
233 opterr = 0;
234 while ((c = getopt(argc, argv, "adp?")) != -1) {
235 switch (c) {
236 case 'a':
237 setall = true;
238 break;
239 case 'd':
240 doDirected = true;
241 break;
242 case 'p':
243 doPath = true;
244 break;
245 case '?':
246 if (optopt == '\0' || optopt == '?')
247 usage(0);
248 else {
249 fprintf(stderr, "%s: option -%c unrecognized\n",
250 CmdName, optopt);
251 usage(1);
252 }
253 break;
254 default:
255 UNREACHABLE();
256 }
257 }
258 argv += optind;
259 argc -= optind;
260
261 if (argc == 0) {
262 fprintf(stderr, "%s: no node specified\n", CmdName);
263 usage(1);
264 }
265 Files = gv_calloc((size_t)argc / 2 + 2, sizeof(char *));
266 Nodes = gv_calloc((size_t)argc / 2 + 2, sizeof(char *));
267 for (j = i = 0; i < argc; i++) {
268 Nodes[j] = argv[i++];
269 Files[j] = argv[i] ? argv[i] : "-";
270 j++;
271 }
272 Nodes[j] = Files[j] = NULL;
273}
274
275int main(int argc, char **argv)
276{
277 Agraph_t *g;
278 Agnode_t *n;
279 ingraph_state ig;
280 size_t i = 0;
281 int code = 0;
282 Dict_t *Q;
283
284 init(argc, argv);
285 newIngraph(&ig, Files);
286
287 Q = dtopen(&MyDisc, Dtoset);
288 while ((g = nextGraph(&ig)) != 0) {
289 dtclear(Q);
290 if ((n = agnode(g, Nodes[i], 0)))
291 dijkstra(Q, g, n);
292 else {
293 fprintf(stderr, "%s: no node %s in graph %s in %s\n",
294 CmdName, Nodes[i], agnameof(g), fileName(&ig));
295 code = 1;
296 }
297 agwrite(g, stdout);
298 fflush(stdout);
299 agclose(g);
300 i++;
301 }
302 free(Nodes);
303 free(Files);
304 graphviz_exit(code);
305}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define dtclear(d)
Definition cdt.h:188
#define dtinsert(d, o)
Definition cdt.h:185
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:304
#define dtdelete(d, o)
Definition cdt.h:186
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
#define dtfirst(d)
Definition cdt.h:179
abstract graph C library, Cgraph API
static void init(int argc, char *argv[])
Definition dijkstra.c:228
#define getprev(n)
Definition dijkstra.c:76
static char ** Nodes
Definition dijkstra.c:31
static Agsym_t * len_sym
Definition dijkstra.c:37
static void setdist(Agnode_t *n, double dist)
Definition dijkstra.c:69
static bool doDirected
Definition dijkstra.c:36
static void dijkstra(Dict_t *Q, Agraph_t *G, Agnode_t *n)
Definition dijkstra.c:188
#define isDone(n)
Definition dijkstra.c:78
static Agnode_t * extract_min(Dict_t *Q)
Definition dijkstra.c:104
static Dtdisc_t MyDisc
Definition dijkstra.c:95
static void update(Dict_t *Q, Agnode_t *dest, Agnode_t *src, double len)
Definition dijkstra.c:112
#define setprev(n, p)
Definition dijkstra.c:77
static bool doPath
Definition dijkstra.c:35
static char * useString
Definition dijkstra.c:214
static bool setall
Definition dijkstra.c:32
static double getlength(Agedge_t *e)
Definition dijkstra.c:46
static double getdist(Agnode_t *n)
Definition dijkstra.c:62
static int cmpf(void *key1, void *key2)
Definition dijkstra.c:81
static char ** Files
Definition dijkstra.c:30
static char * CmdName
Definition dijkstra.c:29
#define setDone(n)
Definition dijkstra.c:79
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
static double dist(int dim, double *x, double *y)
#define G
Definition gdefs.h:7
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
Agsym_t * agattrsym(void *obj, char *name)
looks up a string attribute for a graph object given as an argument
Definition attr.c:156
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:338
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:478
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:455
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:85
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:730
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:145
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:170
void agclean(Agraph_t *g, int kind, char *rec_name)
calls agdelrec for all objects of the same class in an entire graph
Definition rec.c:202
static const char * usage
Definition gvpr.c:51
$2 u p prev
Definition htmlparse.y:297
char * fileName(ingraph_state *sp)
Return name of current file being processed.
Definition ingraphs.c:156
Agraph_t * nextGraph(ingraph_state *sp)
Definition ingraphs.c:61
ingraph_state * newIngraph(ingraph_state *sp, char **files)
Definition ingraphs.c:140
supports user-supplied data
char * post
Definition maze.c:55
char * pre
Definition maze.c:29
PATHUTIL_API COORD dist2(Ppoint_t, Ppoint_t)
Definition visibility.c:120
Agnode_t * node
Definition cgraph.h:272
Agobj_t base
Definition cgraph.h:260
Agrec_t * data
stores programmer-defined data, access with AGDATA
Definition cgraph.h:212
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:637
Definition legal.c:50
Definition cdt.h:100
double dist
Definition dijkstra.c:41
Agnode_t * prev
Definition dijkstra.c:42
Agrec_t hdr
Definition dijkstra.c:40
bool done
true if finished
Definition dijkstra.c:43
int main()
#define UNREACHABLE()
Definition unreachable.h:30