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