SCIP Doxygen Documentation
Loading...
Searching...
No Matches
dijkstra.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file dijkstra.c
26 * @ingroup OTHER_CFILES
27 * @brief C implementation of Dijkstra's algorithm
28 * @author Thorsten Koch
29 * @author Marc Pfetsch
30 */
31
32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <assert.h>
37
38#include "dijkstra.h"
39
40
41/** Check whether the data structures of the graph are valid. */
43 const DIJKSTRA_GRAPH* G /**< directed graph to be checked */
44 )
45{
46 unsigned int count = 0;
47 unsigned int i;
48 unsigned int k;
49
50 if ( G == NULL || G->outbeg == NULL || G->outcnt == NULL || G->weight == NULL || G->head == NULL )
51 abort();
52
53 for (i = 0; i < G->nodes; ++i)
54 {
55 for (k = G->outbeg[i]; k < G->outbeg[i] + G->outcnt[i]; ++k)
56 {
57 if ( G->head[k] >= G->nodes )
58 abort();
59
60 if ( G->weight[k] > G->maxweight || G->weight[k] < G->minweight )
61 abort();
62
63 ++count;
64 }
65 if ( G->head[k] != DIJKSTRA_UNUSED )
66 abort();
67
68 ++count;
69 }
70 if ( count > G->arcs )
71 abort();
72
73 return TRUE;
74}
75
76
77#ifndef NDEBUG
78/** Check whether heap is valid.
79 *
80 * @note Sift up/down do not use order, only for the last the changed one is entered.
81 */
82static
84 const unsigned int* entry, /**< entries of heap */
85 const unsigned long long* value, /**< values in heap */
86 const unsigned int* order, /**< order of entries */
87 const unsigned int used, /**< number of used entries */
88 const unsigned int size /**< size of entry array */
89 )
90{
91 unsigned int i;
92
93 if ( entry == NULL || value == NULL || order == NULL || used > size )
94 return FALSE;
95
96 /* check heap property */
97 for (i = 0; i < used / 2; ++i)
98 {
99 unsigned int child = i + i + 1;
100 if ( value[entry[i]] > value[entry[child]] )
101 return FALSE;
102 if ( child + 1 < used && value[entry[i]] > value[entry[child + 1]] )
103 return FALSE;
104 }
105
106 return TRUE;
107}
108#endif
109
110
111/** Moves an entry down in the vector until the sorting is valid again. */
112static
114 unsigned int* entry, /**< entries of heap */
115 const unsigned long long* value, /**< values in heap */
116 unsigned int* order, /**< order of entries */
117 unsigned int used, /**< number of used entries */
118 unsigned int current /**< current entry to be sifted */
119 )
120{
121 unsigned long long val;
122 unsigned int child;
123 unsigned int ent;
124 unsigned int e;
125
126 child = current + current + 1;
127 ent = entry[current];
128 val = value[ent];
129
130 while ( child < used )
131 {
132 e = entry[child];
133
134 if ( child + 1 < used )
135 {
136 if ( value[entry[child + 1]] < value[e] )
137 {
138 ++child;
139 e = entry[child];
140 }
141 }
142 if ( value[e] >= val )
143 break;
144
145 entry[current] = e;
146 order[e] = current;
147
148 current = child;
149 child += child + 1;
150 }
151 entry[current] = ent;
152 order[ent] = current;
153}
154
155
156/** Moves an entry up in the vector until the sorting is valid again. */
157static
159 unsigned int* entry, /**< entries of heap */
160 const unsigned long long* value, /**< values in heap */
161 unsigned int* order, /**< order of entries */
162 unsigned int current /**< current entry to be sifted */
163 )
164{
165 unsigned long long val;
166 unsigned int parent;
167 unsigned int ent;
168 unsigned int e;
169
170 ent = entry[current];
171 val = value[ent];
172
173 while ( current > 0 )
174 {
175 parent = (current - 1) / 2;
176 e = entry[parent];
177
178 if ( value[e] <= val )
179 break;
180
181 entry[current] = e;
182 order[e] = current;
183 current = parent;
184 }
185 entry[current] = ent;
186 order[ent] = current;
187}
188
189
190/** Dijkstra's algorithm for shortest paths from a single source using binary heaps */
191unsigned int dijkstra(
192 const DIJKSTRA_GRAPH* G, /**< directed graph */
193 unsigned int source, /**< source node */
194 unsigned long long* dist, /**< node distances (allocated by user) */
195 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
196 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
197 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
198 )
199{
200 unsigned long long weight;
201 unsigned int iters = 0;
202 unsigned int used = 0;
203 unsigned int head;
204 unsigned int tail;
205 unsigned int i;
206 unsigned int e;
207
209 assert( source < G->nodes );
210 assert( dist != NULL );
211 assert( pred != NULL );
212
213 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
214
215 /* initialize nodes */
216 for (i = 0; i < G->nodes; ++i)
217 {
218 dist[i] = DIJKSTRA_FARAWAY;
219 order[i] = DIJKSTRA_UNUSED;
220 pred[i] = DIJKSTRA_UNUSED;
221 }
222
223 /* enter source node into heap */
224 entry[0] = source;
225 order[source] = 0;
226 pred[source] = DIJKSTRA_UNUSED;
227 dist[source] = 0;
228
229 ++used;
230
231 /* loop while heap is not empty */
232 while ( used > 0 )
233 {
234 /* get next node */
235 tail = entry[0];
236
237 /* remove node from heap */
238 --used;
239 entry[0] = entry[used];
240 order[entry[0]] = 0;
241 order[tail] = DIJKSTRA_UNUSED;
242
243 dijkstraSiftDown(entry, dist, order, used, 0);
244
245 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
246 assert( entry[used] < G->nodes );
247
248 /* check adjacent nodes */
249 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
250 {
251 head = G->head[e];
252 weight = G->weight[e] + dist[tail];
253
254 /* Can we improve the current shortest path? */
255 if ( dist[head] > weight )
256 {
257 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
258 assert( used < G->nodes );
259 assert( head <= G->nodes );
260
261 pred[head] = tail;
262 dist[head] = weight;
263
264 if ( order[head] == DIJKSTRA_UNUSED )
265 {
266 assert( head < G->nodes );
267
268 entry[used] = head;
269 order[head] = used;
270
271 dijkstraSiftUp(entry, dist, order, used);
272 ++used;
273 }
274 else
275 {
276 dijkstraSiftUp(entry, dist, order, order[head]);
277 }
278 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
279
280 ++iters;
281 }
282 }
283 }
284 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
285
286 return iters;
287}
288
289
290/** Dijkstra's algorithm for shortest paths between a pair of nodes using binary heaps */
291unsigned int dijkstraPair(
292 const DIJKSTRA_GRAPH* G, /**< directed graph */
293 unsigned int source, /**< source node */
294 unsigned int target, /**< target node */
295 unsigned long long* dist, /**< node distances (allocated by user) */
296 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
297 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
298 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
299 )
300{
301 unsigned long long weight;
302 unsigned int iters = 0;
303 unsigned int used = 0;
304 unsigned int head;
305 unsigned int tail;
306 unsigned int i;
307 unsigned int e;
308
310 assert( source < G->nodes );
311 assert( target < G->nodes );
312 assert( dist != NULL );
313 assert( pred != NULL );
314
315 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
316
317 /* initialize nodes */
318 for (i = 0; i < G->nodes; ++i)
319 {
320 dist[i] = DIJKSTRA_FARAWAY;
321 order[i] = DIJKSTRA_UNUSED;
322 pred[i] = DIJKSTRA_UNUSED;
323 }
324
325 /* enter source node into heap */
326 entry[0] = source;
327 order[source] = 0;
328 pred[source] = DIJKSTRA_UNUSED;
329 dist[source] = 0;
330
331 ++used;
332
333 /* loop while heap is not empty */
334 while ( used > 0 )
335 {
336 /* get next node */
337 tail = entry[0];
338
339 /* stop if we have found the target node */
340 if ( tail == target )
341 break;
342
343 /* remove node from heap */
344 --used;
345 entry[0] = entry[used];
346 order[entry[0]] = 0;
347 order[tail] = DIJKSTRA_UNUSED;
348
349 dijkstraSiftDown(entry, dist, order, used, 0);
350
351 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
352 assert( entry[used] < G->nodes );
353
354 /* check adjacent nodes */
355 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
356 {
357 head = G->head[e];
358 weight = G->weight[e] + dist[tail];
359
360 /* Can we improve the current shortest path? */
361 if ( dist[head] > weight )
362 {
363 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
364 assert( used < G->nodes );
365 assert( head <= G->nodes );
366
367 pred[head] = tail;
368 dist[head] = weight;
369
370 if ( order[head] == DIJKSTRA_UNUSED )
371 {
372 assert( head < G->nodes );
373
374 entry[used] = head;
375 order[head] = used;
376
377 dijkstraSiftUp(entry, dist, order, used);
378 ++used;
379 }
380 else
381 {
382 dijkstraSiftUp(entry, dist, order, order[head]);
383 }
384 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
385
386 ++iters;
387 }
388 }
389 }
390 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
391
392 return iters;
393}
394
395
396/** Dijkstra's algorithm for shortest paths between a pair of nodes using binary heaps and truncated at cutoff */
398 const DIJKSTRA_GRAPH* G, /**< directed graph */
399 unsigned int source, /**< source node */
400 unsigned int target, /**< target node */
401 unsigned long long cutoff, /**< if the distance of a node reached this value, we truncate the search */
402 unsigned long long* dist, /**< node distances (allocated by user) */
403 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
404 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
405 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
406 )
407{
408 unsigned long long weight;
409 unsigned int iters = 0;
410 unsigned int used = 0;
411 unsigned int head;
412 unsigned int tail;
413 unsigned int i;
414 unsigned int e;
415
417 assert( source < G->nodes );
418 assert( target < G->nodes );
419 assert( dist != NULL );
420 assert( pred != NULL );
421
422 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
423
424 /* initialize nodes */
425 for (i = 0; i < G->nodes; ++i)
426 {
427 dist[i] = DIJKSTRA_FARAWAY;
428 order[i] = DIJKSTRA_UNUSED;
429 pred[i] = DIJKSTRA_UNUSED;
430 }
431
432 /* enter source node into heap */
433 entry[0] = source;
434 order[source] = 0;
435 pred[source] = DIJKSTRA_UNUSED;
436 dist[source] = 0;
437
438 ++used;
439
440 /* loop while heap is not empty */
441 while ( used > 0 )
442 {
443 /* get next node */
444 tail = entry[0];
445
446 /* stop if we have found the target node */
447 if ( tail == target )
448 break;
449
450 /* remove node from heap */
451 --used;
452 entry[0] = entry[used];
453 order[entry[0]] = 0;
454 order[tail] = DIJKSTRA_UNUSED;
455
456 dijkstraSiftDown(entry, dist, order, used, 0);
457
458 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
459 assert( entry[used] < G->nodes );
460
461 /* only work on nodes if their distance is less than the cutoff */
462 if ( dist[tail] >= cutoff )
463 continue;
464
465 /* check adjacent nodes */
466 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
467 {
468 head = G->head[e];
469 weight = G->weight[e] + dist[tail];
470
471 /* Can we improve the current shortest path? */
472 if ( dist[head] > weight )
473 {
474 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
475 assert( used < G->nodes );
476 assert( head <= G->nodes );
477
478 pred[head] = tail;
479 dist[head] = weight;
480
481 if ( order[head] == DIJKSTRA_UNUSED )
482 {
483 assert( head < G->nodes );
484
485 entry[used] = head;
486 order[head] = used;
487
488 dijkstraSiftUp(entry, dist, order, used);
489 ++used;
490 }
491 else
492 {
493 dijkstraSiftUp(entry, dist, order, order[head]);
494 }
495 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
496
497 ++iters;
498 }
499 }
500 }
501 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
502
503 return iters;
504}
505
506
507/** Dijkstra's algorithm for shortest paths between a pair of nodes ignoring nodes, using binary heaps, and truncated at cutoff */
509 const DIJKSTRA_GRAPH* G, /**< directed graph */
510 unsigned int source, /**< source node */
511 unsigned int target, /**< target node */
512 unsigned int* ignore, /**< marking nodes to be ignored (if value is nonzero) */
513 unsigned long long cutoff, /**< if the distance of a node reached this value, we truncate the search */
514 unsigned long long* dist, /**< node distances (allocated by user) */
515 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
516 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
517 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
518 )
519{
520 unsigned long long weight;
521 unsigned int iters = 0;
522 unsigned int used = 0;
523 unsigned int head;
524 unsigned int tail;
525 unsigned int i;
526 unsigned int e;
527
529 assert( source < G->nodes );
530 assert( target < G->nodes );
531 assert( dist != NULL );
532 assert( pred != NULL );
533 assert( ignore[source] == 0 );
534 assert( ignore[target] == 0 );
535
536 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
537
538 /* initialize nodes */
539 for (i = 0; i < G->nodes; ++i)
540 {
541 dist[i] = DIJKSTRA_FARAWAY;
542 order[i] = DIJKSTRA_UNUSED;
543 pred[i] = DIJKSTRA_UNUSED;
544 }
545
546 /* enter source node into heap */
547 entry[0] = source;
548 order[source] = 0;
549 pred[source] = DIJKSTRA_UNUSED;
550 dist[source] = 0;
551
552 ++used;
553
554 /* loop while heap is not empty */
555 while ( used > 0 )
556 {
557 /* get next node */
558 tail = entry[0];
559
560 /* stop if we have found the target node */
561 if ( tail == target )
562 break;
563
564 /* remove node from heap */
565 --used;
566 entry[0] = entry[used];
567 order[entry[0]] = 0;
568 order[tail] = DIJKSTRA_UNUSED;
569
570 dijkstraSiftDown(entry, dist, order, used, 0);
571
572 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
573 assert( entry[used] < G->nodes );
574
575 /* only work on nodes if their distance is less than the cutoff */
576 if ( dist[tail] >= cutoff )
577 continue;
578
579 /* check adjacent nodes */
580 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
581 {
582 head = G->head[e];
583
584 /* skip ignored nodes */
585 if ( ignore[head] != 0 )
586 continue;
587
588 weight = G->weight[e] + dist[tail];
589
590 /* Can we improve the current shortest path? */
591 if ( dist[head] > weight )
592 {
593 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
594 assert( used < G->nodes );
595 assert( head <= G->nodes );
596
597 pred[head] = tail;
598 dist[head] = weight;
599
600 if ( order[head] == DIJKSTRA_UNUSED )
601 {
602 assert( head < G->nodes );
603
604 entry[used] = head;
605 order[head] = used;
606
607 dijkstraSiftUp(entry, dist, order, used);
608 ++used;
609 }
610 else
611 {
612 dijkstraSiftUp(entry, dist, order, order[head]);
613 }
614 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
615
616 ++iters;
617 }
618 }
619 }
620 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
621
622 return iters;
623}
#define NULL
Definition def.h:255
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
static DIJKSTRA_Bool dijkstraHeapIsValid(const unsigned int *entry, const unsigned long long *value, const unsigned int *order, const unsigned int used, const unsigned int size)
Definition dijkstra.c:83
unsigned int dijkstra(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:191
static void dijkstraSiftUp(unsigned int *entry, const unsigned long long *value, unsigned int *order, unsigned int current)
Definition dijkstra.c:158
static void dijkstraSiftDown(unsigned int *entry, const unsigned long long *value, unsigned int *order, unsigned int used, unsigned int current)
Definition dijkstra.c:113
unsigned int dijkstraPair(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned int target, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:291
unsigned int dijkstraPairCutoffIgnore(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned int target, unsigned int *ignore, unsigned long long cutoff, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:508
DIJKSTRA_Bool dijkstraGraphIsValid(const DIJKSTRA_GRAPH *G)
Definition dijkstra.c:42
unsigned int dijkstraPairCutoff(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned int target, unsigned long long cutoff, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:397
Definitions for Disjkstra's shortest path algorithm.
#define DIJKSTRA_UNUSED
Definition dijkstra.h:48
#define DIJKSTRA_FARAWAY
Definition dijkstra.h:47
struct DIJKSTRA_Graph DIJKSTRA_GRAPH
Definition dijkstra.h:65
#define DIJKSTRA_Bool
Definition dijkstra.h:40
SCIP_Bool cutoff
assert(minobj< SCIPgetCutoffbound(scip))
unsigned int arcs
Definition dijkstra.h:57
unsigned int minweight
Definition dijkstra.h:60
unsigned int * head
Definition dijkstra.h:59
unsigned int * outbeg
Definition dijkstra.h:55
unsigned int nodes
Definition dijkstra.h:54
unsigned int * weight
Definition dijkstra.h:58
unsigned int * outcnt
Definition dijkstra.h:56
unsigned int maxweight
Definition dijkstra.h:61