Graphviz 14.0.5~dev.20251126.0104
Loading...
Searching...
No Matches
dijkstra.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/******************************************
13
14 Dijkstra algorithm
15 Computes single-source distances for
16 weighted graphs
17
18******************************************/
19
20#include <assert.h>
21#include <float.h>
22#include <neatogen/bfs.h>
23#include <neatogen/dijkstra.h>
24#include <limits.h>
25#include <stdbool.h>
26#include <stdlib.h>
27#include <util/alloc.h>
28#include <util/gv_math.h>
29#include <util/bitarray.h>
30
31typedef DistType Word;
32
33#define MAX_DIST ((DistType)INT_MAX)
34
35/* This heap class is suited to the Dijkstra alg.
36 data[i]=vertexNum <==> index[vertexNum]=i
37*/
38
39static int left(int i) { return 2 * i; }
40
41static int right(int i) { return 2 * i + 1; }
42
43static int parent(int i) { return i / 2; }
44
45typedef struct {
46 int *data;
48 int *index;
49} heap;
50
51static bool insideHeap(const heap *h, int i) { return i < h->heapSize; }
52
53static bool greaterPriority(const heap *h, int i, int j, const Word *dist) {
54 return dist[h->data[i]] < dist[h->data[j]];
55}
56
57static bool greaterPriority_f(const heap *h, int i, int j, const float *dist) {
58 return dist[h->data[i]] < dist[h->data[j]];
59}
60
61static void assign(heap *h, int i, int j) {
62 h->data[i] = h->data[j];
63 h->index[h->data[i]] = i;
64}
65
66static void exchange(heap *h, int i, int j) {
67 SWAP(&h->data[i], &h->data[j]);
68 h->index[h->data[i]] = i;
69 h->index[h->data[j]] = j;
70}
71
72static void heapify(heap *h, int i, Word dist[]) {
73 int l, r, largest;
74 while (1) {
75 l = left(i);
76 r = right(i);
77 if (insideHeap(h, l) && greaterPriority(h, l, i, dist))
78 largest = l;
79 else
80 largest = i;
81 if (insideHeap(h, r) && greaterPriority(h, r, largest, dist))
82 largest = r;
83
84 if (largest == i)
85 break;
86
87 exchange(h, largest, i);
88 i = largest;
89 }
90}
91
92static void freeHeap(heap * h)
93{
94 free(h->index);
95 free(h->data);
96}
97
98static heap initHeap(int startVertex, Word dist[], int n) {
99 int i, count;
100 int j; /* We cannot use an unsigned value in this loop */
101 heap h = {
102 .data = gv_calloc(n - 1, sizeof(int)),
103 .heapSize = n - 1,
104 .index = gv_calloc(n, sizeof(int))
105 };
106
107 for (count = 0, i = 0; i < n; i++)
108 if (i != startVertex) {
109 h.data[count] = i;
110 h.index[i] = count;
111 count++;
112 }
113
114 for (j = (n - 1) / 2; j >= 0; j--)
115 heapify(&h, j, dist);
116
117 return h;
118}
119
120static bool extractMax(heap *h, int *max, Word dist[]) {
121 if (h->heapSize == 0)
122 return false;
123
124 *max = h->data[0];
125 h->data[0] = h->data[h->heapSize - 1];
126 h->index[h->data[0]] = 0;
127 h->heapSize--;
128 heapify(h, 0, dist);
129
130 return true;
131}
132
133static void increaseKey(heap *h, int increasedVertex, Word newDist, Word dist[]) {
134 int placeInHeap;
135 int i;
136
137 if (dist[increasedVertex] <= newDist)
138 return;
139
140 placeInHeap = h->index[increasedVertex];
141
142 dist[increasedVertex] = newDist;
143
144 i = placeInHeap;
145 while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */
146 assign(h, i, parent(i));
147 i = parent(i);
148 }
149 h->data[i] = increasedVertex;
150 h->index[increasedVertex] = i;
151}
152
154{
155 int closestVertex, neighbor;
156 DistType closestDist, prevClosestDist = MAX_DIST;
157
158 /* initial distances with edge weights: */
159 for (int i = 0; i < n; i++)
160 dist[i] = MAX_DIST;
161 dist[vertex] = 0;
162 for (size_t i = 1; i < graph[vertex].nedges; i++)
163 dist[graph[vertex].edges[i]] = (DistType) graph[vertex].ewgts[i];
164
165 heap H = initHeap(vertex, dist, n);
166
167 while (extractMax(&H, &closestVertex, dist)) {
168 closestDist = dist[closestVertex];
169 if (closestDist == MAX_DIST)
170 break;
171 for (size_t i = 1; i < graph[closestVertex].nedges; i++) {
172 neighbor = graph[closestVertex].edges[i];
173 increaseKey(&H, neighbor, closestDist +
174 (DistType)graph[closestVertex].ewgts[i], dist);
175 }
176 prevClosestDist = closestDist;
177 }
178
179 /* For dealing with disconnected graphs: */
180 for (int i = 0; i < n; i++)
181 if (dist[i] == MAX_DIST) /* 'i' is not connected to 'vertex' */
182 dist[i] = prevClosestDist + 10;
183 freeHeap(&H);
184}
185
186static void heapify_f(heap *h, int i, float dist[]) {
187 int l, r, largest;
188 while (1) {
189 l = left(i);
190 r = right(i);
191 if (insideHeap(h, l) && greaterPriority_f(h, l, i, dist))
192 largest = l;
193 else
194 largest = i;
195 if (insideHeap(h, r) && greaterPriority_f(h, r, largest, dist))
196 largest = r;
197
198 if (largest == i)
199 break;
200
201 exchange(h, largest, i);
202 i = largest;
203 }
204}
205
206static heap initHeap_f(int startVertex, float dist[], int n) {
207 int i, count;
208 int j; /* We cannot use an unsigned value in this loop */
209 heap h = {
210 .data = gv_calloc(n - 1, sizeof(int)),
211 .heapSize = n - 1,
212 .index = gv_calloc(n, sizeof(int))
213 };
214
215 for (count = 0, i = 0; i < n; i++)
216 if (i != startVertex) {
217 h.data[count] = i;
218 h.index[i] = count;
219 count++;
220 }
221
222 for (j = (n - 1) / 2; j >= 0; j--)
223 heapify_f(&h, j, dist);
224
225 return h;
226}
227
228static bool extractMax_f(heap *h, int *max, float dist[]) {
229 if (h->heapSize == 0)
230 return false;
231
232 *max = h->data[0];
233 h->data[0] = h->data[h->heapSize - 1];
234 h->index[h->data[0]] = 0;
235 h->heapSize--;
236 heapify_f(h, 0, dist);
237
238 return true;
239}
240
241static void increaseKey_f(heap *h, int increasedVertex, float newDist,
242 float dist[]) {
243 int placeInHeap;
244 int i;
245
246 if (dist[increasedVertex] <= newDist)
247 return;
248
249 placeInHeap = h->index[increasedVertex];
250
251 dist[increasedVertex] = newDist;
252
253 i = placeInHeap;
254 while (i > 0 && dist[h->data[parent(i)]] > newDist) { /* can write here: greaterPriority(i,parent(i),dist) */
255 assign(h, i, parent(i));
256 i = parent(i);
257 }
258 h->data[i] = increasedVertex;
259 h->index[increasedVertex] = i;
260}
261
262/* Weighted shortest paths from vertex.
263 * Assume graph is connected.
264 */
265void dijkstra_f(int vertex, vtx_data * graph, int n, float *dist)
266{
267 int closestVertex = 0, neighbor;
268 float closestDist;
269
270 /* initial distances with edge weights: */
271 for (int i = 0; i < n; i++)
272 dist[i] = FLT_MAX;
273 dist[vertex] = 0;
274 for (size_t i = 1; i < graph[vertex].nedges; i++)
275 dist[graph[vertex].edges[i]] = graph[vertex].ewgts[i];
276
277 heap H = initHeap_f(vertex, dist, n);
278
279 while (extractMax_f(&H, &closestVertex, dist)) {
280 closestDist = dist[closestVertex];
281 if (closestDist == FLT_MAX)
282 break;
283 for (size_t i = 1; i < graph[closestVertex].nedges; i++) {
284 neighbor = graph[closestVertex].edges[i];
285 increaseKey_f(&H, neighbor, closestDist + graph[closestVertex].ewgts[i],
286 dist);
287 }
288 }
289
290 freeHeap(&H);
291}
292
293// single source shortest paths that also builds terms as it goes
294// mostly copied from dijkstra_f above
295// returns the number of terms built
296int dijkstra_sgd(graph_sgd *graph, int source, term_sgd *terms) {
297 float *dists = gv_calloc(graph->n, sizeof(float));
298 for (size_t i= 0; i < graph->n; i++) {
299 dists[i] = FLT_MAX;
300 }
301 dists[source] = 0;
302 for (size_t i = graph->sources[source]; i < graph->sources[source + 1];
303 i++) {
304 size_t target = graph->targets[i];
305 dists[target] = graph->weights[i];
306 }
307 assert(graph->n <= INT_MAX);
308 heap h = initHeap_f(source, dists, (int)graph->n);
309
310 int closest = 0, offset = 0;
311 while (extractMax_f(&h, &closest, dists)) {
312 float d = dists[closest];
313 if (d == FLT_MAX) {
314 break;
315 }
316 // if the target is fixed then always create a term as shortest paths are not calculated from there
317 // if not fixed then only create a term if the target index is lower
318 if (bitarray_get(graph->pinneds, closest) || closest<source) {
319 terms[offset].i = source;
320 terms[offset].j = closest;
321 terms[offset].d = d;
322 terms[offset].w = 1 / (d*d);
323 offset++;
324 }
325 for (size_t i = graph->sources[closest]; i < graph->sources[closest + 1];
326 i++) {
327 size_t target = graph->targets[i];
328 float weight = graph->weights[i];
329 assert(target <= INT_MAX);
330 increaseKey_f(&h, (int)target, d+weight, dists);
331 }
332 }
333 freeHeap(&h);
334 free(dists);
335 return offset;
336}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
API for compacted arrays of booleans.
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
Definition bitarray.h:65
#define greaterPriority(h, i, j)
Definition closest.c:75
#define parent(i)
Definition closest.c:73
#define right(i)
Definition closest.c:72
#define insideHeap(h, i)
Definition closest.c:74
#define left
Definition dthdr.h:12
static double dist(int dim, double *x, double *y)
void free(void *)
Agraph_t * graph(char *name)
Definition gv.cpp:32
Arithmetic helper functions.
#define SWAP(a, b)
Definition gv_math.h:134
DistType Word
Definition dijkstra.c:31
static void exchange(heap *h, int i, int j)
Definition dijkstra.c:66
static bool extractMax(heap *h, int *max, Word dist[])
Definition dijkstra.c:120
static void freeHeap(heap *h)
Definition dijkstra.c:92
static heap initHeap(int startVertex, Word dist[], int n)
Definition dijkstra.c:98
static heap initHeap_f(int startVertex, float dist[], int n)
Definition dijkstra.c:206
static bool extractMax_f(heap *h, int *max, float dist[])
Definition dijkstra.c:228
static void heapify_f(heap *h, int i, float dist[])
Definition dijkstra.c:186
void dijkstra_f(int vertex, vtx_data *graph, int n, float *dist)
Definition dijkstra.c:265
static bool greaterPriority_f(const heap *h, int i, int j, const float *dist)
Definition dijkstra.c:57
static void increaseKey(heap *h, int increasedVertex, Word newDist, Word dist[])
Definition dijkstra.c:133
void ngdijkstra(int vertex, vtx_data *graph, int n, DistType *dist)
Definition dijkstra.c:153
static void assign(heap *h, int i, int j)
Definition dijkstra.c:61
int dijkstra_sgd(graph_sgd *graph, int source, term_sgd *terms)
Definition dijkstra.c:296
static void heapify(heap *h, int i, Word dist[])
Definition dijkstra.c:72
#define MAX_DIST
Definition dijkstra.c:33
static void increaseKey_f(heap *h, int increasedVertex, float newDist, float dist[])
Definition dijkstra.c:241
#define neighbor(t, i, edim, elist)
Definition make_map.h:41
int DistType
Definition sparsegraph.h:38
int * index
Definition dijkstra.c:48
int * data
Definition dijkstra.c:46
int heapSize
Definition dijkstra.c:47
Definition sgd.h:11
float d
Definition sgd.h:13
int j
Definition sgd.h:12
float w
Definition sgd.h:13
int i
Definition sgd.h:12
Definition legal.c:32