Graphviz 14.1.2~dev.20260118.1035
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 <stddef.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <math.h>
23#include <cgraph/cgraph.h>
24#include <cgraph/ingraphs.h>
25#include <getopt.h>
26#include <util/agxbuf.h>
27#include <util/alloc.h>
28#include <util/exit.h>
29#include <util/gv_math.h>
30#include <util/unreachable.h>
31
32static char *CmdName;
33static char **Files;
34static char **Nodes;
35static bool setall; /* if false, don't set dist attribute for
36 * nodes in different components.
37 */
38static bool doPath; /* if true, record shortest paths */
39static bool doDirected; /* if true, use directed paths */
41
42typedef struct {
44 double dist; /* always positive for scanned nodes */
46 bool done;
48
49static double getlength(Agedge_t * e)
50{
51 double len;
52 char* lens;
53 char* p;
54
55 if (len_sym && (*(lens = agxget(e, len_sym)))) {
56 len = strtod (lens, &p);
57 if (len < 0 || p == lens)
58 len = 1;
59 }
60 else
61 len = 1;
62 return len;
63}
64
65static double getdist(Agnode_t * n)
66{
67 nodedata_t *const data =
68 (nodedata_t *)((char *)n->base.data - offsetof(nodedata_t, hdr));
69 return data->dist;
70}
71
72static void setdist(Agnode_t * n, double dist)
73{
74 nodedata_t *const data =
75 (nodedata_t *)((char *)n->base.data - offsetof(nodedata_t, hdr));
76 data->dist = dist;
77}
78
79#define getprev(n) (((nodedata_t*)((n)->base.data))->prev)
80#define setprev(n,p) (((nodedata_t*)((n)->base.data))->prev = (p))
81#define isDone(n) (((nodedata_t*)((n)->base.data))->done)
82#define setDone(n) (((nodedata_t*)((n)->base.data))->done = true)
83
84static int cmpf(void *key1, void *key2) {
85 const double dist1 = getdist(key1);
86 const double dist2 = getdist(key2);
87 if (dist1 < dist2)
88 return -1;
89 if (dist1 > dist2)
90 return 1;
91 if (key1 < key2)
92 return -1;
93 if (key1 > key2)
94 return 1;
95 return 0;
96}
97
98static Dtdisc_t MyDisc = {
99 0, /* int key */
100 0, /* int size */
101 -1, /* int link */
102 0, /* Dtmake_f makef */
103 0, /* Dtfree_f freef */
104 cmpf, /* Dtcompar_f comparf */
105};
106
108{
109 Agnode_t *rv;
110 rv = dtfirst(Q);
111 dtdelete(Q, rv);
112 return rv;
113}
114
115static void update(Dict_t * Q, Agnode_t * dest, Agnode_t * src, double len)
116{
117 double newlen = getdist(src) + len;
118 double oldlen = getdist(dest);
119
120 if (is_exactly_zero(oldlen)) { // first time to see dest
121 setdist(dest, newlen);
122 if (doPath) setprev(dest, src);
123 dtinsert(Q, dest);
124 } else if (newlen < oldlen) {
125 dtdelete(Q, dest);
126 setdist(dest, newlen);
127 if (doPath) setprev(dest, src);
128 dtinsert(Q, dest);
129 }
130}
131
132static void pre(Agraph_t * g)
133{
134 len_sym = agattr_text(g, AGEDGE, "len", NULL);
135 aginit(g, AGNODE, "dijkstra", sizeof(nodedata_t), true);
136}
137
138static void post(Agraph_t * g)
139{
140 Agnode_t *v;
141 Agnode_t *prev;
142 agxbuf buf = {0};
143 agxbuf dflt_buf = {0};
144 Agsym_t *sym;
145 Agsym_t *psym = NULL;
146 double dist, oldmax;
147 double maxdist = 0.0; /* maximum "finite" distance */
148
149 sym = agattr_text(g, AGNODE, "dist", "");
150 if (doPath)
151 psym = agattr_text(g, AGNODE, "prev", "");
152
153 if (setall)
154 agxbprint(&dflt_buf, "%.3lf", HUGE_VAL);
155 const char *const dflt = agxbuse(&dflt_buf);
156
157 for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
158 dist = getdist(v);
159 if (!is_exactly_zero(dist)) {
160 dist--;
161 agxbprint(&buf, "%.3lf", dist);
162 agxset(v, sym, agxbuse(&buf));
163 if (doPath && (prev = getprev(v)))
164 agxset(v, psym, agnameof(prev));
165 if (maxdist < dist)
166 maxdist = dist;
167 } else if (setall)
168 agxset(v, sym, dflt);
169 }
170
171 sym = agattrsym(g, "maxdist");
172 if (sym) {
173 if (!setall) {
174 /* if we are preserving distances in other components,
175 * check previous value of maxdist.
176 */
177 oldmax = atof(agxget(g, sym));
178 if (oldmax > maxdist)
179 maxdist = oldmax;
180 }
181 agxbprint(&buf, "%.3lf", maxdist);
182 agxset(g, sym, agxbuse(&buf));
183 } else {
184 agxbprint(&buf, "%.3lf", maxdist);
185 agattr_text(g, AGRAPH, "maxdist", agxbuse(&buf));
186 }
187
188 agxbfree(&dflt_buf);
189 agxbfree(&buf);
190 agclean(g, AGNODE, "dijkstra");
191 agclean(g, AGEDGE, "dijkstra");
192}
193
194static void dijkstra(Dict_t * Q, Agraph_t * G, Agnode_t * n)
195{
196 Agnode_t *u;
197 Agedge_t *e;
198
199 pre(G);
200 setdist(n, 1);
201 dtinsert(Q, n);
202 if (doDirected) {
203 while ((u = extract_min(Q))) {
204 setDone (u);
205 for (e = agfstout(G, u); e; e = agnxtout(G, e)) {
206 if (!isDone(e->node)) update(Q, e->node, u, getlength(e));
207 }
208 }
209 } else {
210 while ((u = extract_min(Q))) {
211 setDone (u);
212 for (e = agfstedge(G, u); e; e = agnxtedge(G, e, u)) {
213 if (!isDone(e->node)) update(Q, e->node, u, getlength(e));
214 }
215 }
216 }
217 post(G);
218}
219
220static char *useString =
221 "Usage: dijkstra [-ap?] <node> [<file> <node> <file>]\n\
222 -a - for nodes in a different component, set dist very large\n\
223 -d - use forward directed edges\n\
224 -p - attach shortest path info\n\
225 -? - print usage\n\
226If no files are specified, stdin is used\n";
227
228static void usage(int v)
229{
230 printf("%s",useString);
231 graphviz_exit(v);
232}
233
234static void init(int argc, char *argv[])
235{
236 int i, j, c;
237
238 CmdName = argv[0];
239 opterr = 0;
240 while ((c = getopt(argc, argv, "adp?")) != -1) {
241 switch (c) {
242 case 'a':
243 setall = true;
244 break;
245 case 'd':
246 doDirected = true;
247 break;
248 case 'p':
249 doPath = true;
250 break;
251 case '?':
252 if (optopt == '\0' || optopt == '?')
253 usage(0);
254 else {
255 fprintf(stderr, "%s: option -%c unrecognized\n",
256 CmdName, optopt);
257 usage(1);
258 }
259 break;
260 default:
261 UNREACHABLE();
262 }
263 }
264 argv += optind;
265 argc -= optind;
266
267 if (argc == 0) {
268 fprintf(stderr, "%s: no node specified\n", CmdName);
269 usage(1);
270 }
271 Files = gv_calloc((size_t)argc / 2 + 2, sizeof(char *));
272 Nodes = gv_calloc((size_t)argc / 2 + 2, sizeof(char *));
273 for (j = i = 0; i < argc; i++) {
274 Nodes[j] = argv[i++];
275 Files[j] = argv[i] ? argv[i] : "-";
276 j++;
277 }
278 Nodes[j] = Files[j] = NULL;
279}
280
281int main(int argc, char **argv)
282{
283 Agraph_t *g;
284 Agnode_t *n;
285 ingraph_state ig;
286 size_t i = 0;
287 int code = 0;
288 Dict_t *Q;
289
290 init(argc, argv);
291 newIngraph(&ig, Files);
292
293 Q = dtopen(&MyDisc, Dtoset);
294 while ((g = nextGraph(&ig)) != 0) {
295 dtclear(Q);
296 if ((n = agnode(g, Nodes[i], 0)))
297 dijkstra(Q, g, n);
298 else {
299 fprintf(stderr, "%s: no node %s in graph %s in %s\n",
300 CmdName, Nodes[i], agnameof(g), fileName(&ig));
301 code = 1;
302 }
303 agwrite(g, stdout);
304 fflush(stdout);
305 agclose(g);
306 i++;
307 }
308 free(Nodes);
309 free(Files);
310 graphviz_exit(code);
311}
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
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:189
#define dtinsert(d, o)
Definition cdt.h:186
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:306
#define dtdelete(d, o)
Definition cdt.h:187
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:11
#define dtfirst(d)
Definition cdt.h:180
abstract graph C library, Cgraph API
static void init(int argc, char *argv[])
Definition dijkstra.c:234
#define getprev(n)
Definition dijkstra.c:79
static char ** Nodes
Definition dijkstra.c:34
static Agsym_t * len_sym
Definition dijkstra.c:40
static void setdist(Agnode_t *n, double dist)
Definition dijkstra.c:72
static bool doDirected
Definition dijkstra.c:39
static void dijkstra(Dict_t *Q, Agraph_t *G, Agnode_t *n)
Definition dijkstra.c:194
#define isDone(n)
Definition dijkstra.c:81
static Agnode_t * extract_min(Dict_t *Q)
Definition dijkstra.c:107
static Dtdisc_t MyDisc
Definition dijkstra.c:98
static void update(Dict_t *Q, Agnode_t *dest, Agnode_t *src, double len)
Definition dijkstra.c:115
#define setprev(n, p)
Definition dijkstra.c:80
static bool doPath
Definition dijkstra.c:38
static char * useString
Definition dijkstra.c:220
static bool setall
Definition dijkstra.c:35
static double getlength(Agedge_t *e)
Definition dijkstra.c:49
static double getdist(Agnode_t *n)
Definition dijkstra.c:65
static int cmpf(void *key1, void *key2)
Definition dijkstra.c:84
static char ** Files
Definition dijkstra.c:33
static char * CmdName
Definition dijkstra.c:32
#define setDone(n)
Definition dijkstra.c:82
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:138
void free(void *)
node NULL
Definition grammar.y:181
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:336
Agsym_t * agattrsym(void *obj, char *name)
looks up a string attribute for a graph object given as an argument
Definition attr.c:146
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:524
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:460
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:97
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:669
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:143
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
@ 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:172
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:204
Arithmetic helper functions.
static bool is_exactly_zero(double v)
is a value precisely 0.0?
Definition gv_math.h:67
static const char * usage
Definition gvpr.c:54
$2 prev
Definition htmlparse.y:291
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:58
char * pre
Definition maze.c:32
PATHUTIL_API COORD dist2(Ppoint_t, Ppoint_t)
Definition visibility.c:122
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:424
implementation of Agrec_t
Definition cgraph.h:172
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
Definition cdt.h:98
double dist
Definition dijkstra.c:44
Agnode_t * prev
Definition dijkstra.c:45
Agrec_t hdr
Definition dijkstra.c:43
bool done
true if finished
Definition dijkstra.c:46
int main()
#define UNREACHABLE()
Definition unreachable.h:30