Scippy

SCIP

Solving Constraint Integer Programs

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-2024 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 if ( value[entry[i]] > value[entry[i + i]] )
100 return FALSE;
101 if ( i + i + 1 < used && value[entry[i]] > value[entry[i + i + 1]] )
102 return FALSE;
103 }
104
105 return TRUE;
106}
107#endif
108
109
110/** Moves an entry down in the vector until the sorting is valid again. */
111static
113 unsigned int* entry, /**< entries of heap */
114 const unsigned long long* value, /**< values in heap */
115 unsigned int* order, /**< order of entries */
116 unsigned int used, /**< number of used entries */
117 unsigned int current /**< current entry to be sifted */
118 )
119{
120 unsigned long long val;
121 unsigned int child;
122 unsigned int ent;
123 unsigned int e;
124
125 child = current + current;
126 ent = entry[current];
127 val = value[ent];
128
129 while ( child < used )
130 {
131 e = entry[child];
132
133 if ( child + 1 < used )
134 {
135 if ( value[entry[child + 1]] < value[e] )
136 {
137 ++child;
138 e = entry[child];
139 }
140 }
141 if ( value[e] >= val )
142 break;
143
144 entry[current] = e;
145 order[e] = current;
146
147 current = child;
148 child += child;
149 }
150 entry[current] = ent;
151 order[ent] = current;
152}
153
154
155/** Moves an entry up in the vector until the sorting is valid again. */
156static
158 unsigned int* entry, /**< entries of heap */
159 const unsigned long long* value, /**< values in heap */
160 unsigned int* order, /**< order of entries */
161 unsigned int current /**< current entry to be sifted */
162 )
163{
164 unsigned long long val;
165 unsigned int parent;
166 unsigned int ent;
167 unsigned int e;
168
169 ent = entry[current];
170 val = value[ent];
171
172 while ( current > 0 )
173 {
174 parent = current / 2;
175 e = entry[parent];
176
177 if ( value[e] <= val )
178 break;
179
180 entry[current] = e;
181 order[e] = current;
182 current = parent;
183 }
184 entry[current] = ent;
185 order[ent] = current;
186}
187
188
189/** Dijkstra's algorithm for shortest paths from a single source using binary heaps */
190unsigned int dijkstra(
191 const DIJKSTRA_GRAPH* G, /**< directed graph */
192 unsigned int source, /**< source node */
193 unsigned long long* dist, /**< node distances (allocated by user) */
194 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
195 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
196 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
197 )
198{
199 unsigned long long weight;
200 unsigned int iters = 0;
201 unsigned int used = 0;
202 unsigned int head;
203 unsigned int tail;
204 unsigned int i;
205 unsigned int e;
206
207 assert( dijkstraGraphIsValid(G) );
208 assert( source < G->nodes );
209 assert( dist != NULL );
210 assert( pred != NULL );
211
212 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
213
214 /* initialize nodes */
215 for (i = 0; i < G->nodes; ++i)
216 {
217 dist[i] = DIJKSTRA_FARAWAY;
218 order[i] = DIJKSTRA_UNUSED;
219 pred[i] = DIJKSTRA_UNUSED;
220 }
221
222 /* enter source node into heap */
223 entry[0] = source;
224 order[source] = 0;
225 pred[source] = DIJKSTRA_UNUSED;
226 dist[source] = 0;
227
228 ++used;
229
230 /* loop while heap is not empty */
231 while ( used > 0 )
232 {
233 /* get next node */
234 tail = entry[0];
235
236 /* remove node from heap */
237 --used;
238 entry[0] = entry[used];
239 order[entry[0]] = 0;
240 order[tail] = DIJKSTRA_UNUSED;
241
242 dijkstraSiftDown(entry, dist, order, used, 0);
243
244 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
245 assert( entry[used] < G->nodes );
246
247 /* check adjacent nodes */
248 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
249 {
250 head = G->head[e];
251 weight = G->weight[e] + dist[tail];
252
253 /* Can we improve the current shortest path? */
254 if ( dist[head] > weight )
255 {
256 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
257 assert( used < G->nodes );
258 assert( head <= G->nodes );
259
260 pred[head] = tail;
261 dist[head] = weight;
262
263 if ( order[head] == DIJKSTRA_UNUSED )
264 {
265 assert( head < G->nodes );
266
267 entry[used] = head;
268 order[head] = used;
269
270 dijkstraSiftUp(entry, dist, order, used);
271 ++used;
272 }
273 else
274 {
275 dijkstraSiftUp(entry, dist, order, order[head]);
276 }
277 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
278
279 ++iters;
280 }
281 }
282 }
283 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
284
285 return iters;
286}
287
288
289/** Dijkstra's algorithm for shortest paths between a pair of nodes using binary heaps */
290unsigned int dijkstraPair(
291 const DIJKSTRA_GRAPH* G, /**< directed graph */
292 unsigned int source, /**< source node */
293 unsigned int target, /**< target node */
294 unsigned long long* dist, /**< node distances (allocated by user) */
295 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
296 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
297 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
298 )
299{
300 unsigned long long weight;
301 unsigned int iters = 0;
302 unsigned int used = 0;
303 unsigned int head;
304 unsigned int tail;
305 unsigned int i;
306 unsigned int e;
307
308 assert( dijkstraGraphIsValid(G) );
309 assert( source < G->nodes );
310 assert( target < G->nodes );
311 assert( dist != NULL );
312 assert( pred != NULL );
313
314 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
315
316 /* initialize nodes */
317 for (i = 0; i < G->nodes; ++i)
318 {
319 dist[i] = DIJKSTRA_FARAWAY;
320 order[i] = DIJKSTRA_UNUSED;
321 pred[i] = DIJKSTRA_UNUSED;
322 }
323
324 /* enter source node into heap */
325 entry[0] = source;
326 order[source] = 0;
327 pred[source] = DIJKSTRA_UNUSED;
328 dist[source] = 0;
329
330 ++used;
331
332 /* loop while heap is not empty */
333 while ( used > 0 )
334 {
335 /* get next node */
336 tail = entry[0];
337
338 /* stop if we have found the target node */
339 if ( tail == target )
340 break;
341
342 /* remove node from heap */
343 --used;
344 entry[0] = entry[used];
345 order[entry[0]] = 0;
346 order[tail] = DIJKSTRA_UNUSED;
347
348 dijkstraSiftDown(entry, dist, order, used, 0);
349
350 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
351 assert( entry[used] < G->nodes );
352
353 /* check adjacent nodes */
354 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
355 {
356 head = G->head[e];
357 weight = G->weight[e] + dist[tail];
358
359 /* Can we improve the current shortest path? */
360 if ( dist[head] > weight )
361 {
362 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
363 assert( used < G->nodes );
364 assert( head <= G->nodes );
365
366 pred[head] = tail;
367 dist[head] = weight;
368
369 if ( order[head] == DIJKSTRA_UNUSED )
370 {
371 assert( head < G->nodes );
372
373 entry[used] = head;
374 order[head] = used;
375
376 dijkstraSiftUp(entry, dist, order, used);
377 ++used;
378 }
379 else
380 {
381 dijkstraSiftUp(entry, dist, order, order[head]);
382 }
383 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
384
385 ++iters;
386 }
387 }
388 }
389 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
390
391 return iters;
392}
393
394
395/** Dijkstra's algorithm for shortest paths between a pair of nodes using binary heaps and truncated at cutoff */
397 const DIJKSTRA_GRAPH* G, /**< directed graph */
398 unsigned int source, /**< source node */
399 unsigned int target, /**< target node */
400 unsigned long long cutoff, /**< if the distance of a node reached this value, we truncate the search */
401 unsigned long long* dist, /**< node distances (allocated by user) */
402 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
403 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
404 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
405 )
406{
407 unsigned long long weight;
408 unsigned int iters = 0;
409 unsigned int used = 0;
410 unsigned int head;
411 unsigned int tail;
412 unsigned int i;
413 unsigned int e;
414
415 assert( dijkstraGraphIsValid(G) );
416 assert( source < G->nodes );
417 assert( target < G->nodes );
418 assert( dist != NULL );
419 assert( pred != NULL );
420
421 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
422
423 /* initialize nodes */
424 for (i = 0; i < G->nodes; ++i)
425 {
426 dist[i] = DIJKSTRA_FARAWAY;
427 order[i] = DIJKSTRA_UNUSED;
428 pred[i] = DIJKSTRA_UNUSED;
429 }
430
431 /* enter source node into heap */
432 entry[0] = source;
433 order[source] = 0;
434 pred[source] = DIJKSTRA_UNUSED;
435 dist[source] = 0;
436
437 ++used;
438
439 /* loop while heap is not empty */
440 while ( used > 0 )
441 {
442 /* get next node */
443 tail = entry[0];
444
445 /* stop if we have found the target node */
446 if ( tail == target )
447 break;
448
449 /* remove node from heap */
450 --used;
451 entry[0] = entry[used];
452 order[entry[0]] = 0;
453 order[tail] = DIJKSTRA_UNUSED;
454
455 dijkstraSiftDown(entry, dist, order, used, 0);
456
457 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
458 assert( entry[used] < G->nodes );
459
460 /* only work on nodes if their distance is less than the cutoff */
461 if ( dist[tail] >= cutoff )
462 continue;
463
464 /* check adjacent nodes */
465 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
466 {
467 head = G->head[e];
468 weight = G->weight[e] + dist[tail];
469
470 /* Can we improve the current shortest path? */
471 if ( dist[head] > weight )
472 {
473 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
474 assert( used < G->nodes );
475 assert( head <= G->nodes );
476
477 pred[head] = tail;
478 dist[head] = weight;
479
480 if ( order[head] == DIJKSTRA_UNUSED )
481 {
482 assert( head < G->nodes );
483
484 entry[used] = head;
485 order[head] = used;
486
487 dijkstraSiftUp(entry, dist, order, used);
488 ++used;
489 }
490 else
491 {
492 dijkstraSiftUp(entry, dist, order, order[head]);
493 }
494 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
495
496 ++iters;
497 }
498 }
499 }
500 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
501
502 return iters;
503}
504
505
506/** Dijkstra's algorithm for shortest paths between a pair of nodes ignoring nodes, using binary heaps, and truncated at cutoff */
508 const DIJKSTRA_GRAPH* G, /**< directed graph */
509 unsigned int source, /**< source node */
510 unsigned int target, /**< target node */
511 unsigned int* ignore, /**< marking nodes to be ignored (if value is nonzero) */
512 unsigned long long cutoff, /**< if the distance of a node reached this value, we truncate the search */
513 unsigned long long* dist, /**< node distances (allocated by user) */
514 unsigned int* pred, /**< node predecessors in final shortest path tree (allocated by user) */
515 unsigned int* entry, /**< temporary storage (for each node - must be allocated by user) */
516 unsigned int* order /**< temporary storage (for each node - must be allocated by user) */
517 )
518{
519 unsigned long long weight;
520 unsigned int iters = 0;
521 unsigned int used = 0;
522 unsigned int head;
523 unsigned int tail;
524 unsigned int i;
525 unsigned int e;
526
527 assert( dijkstraGraphIsValid(G) );
528 assert( source < G->nodes );
529 assert( target < G->nodes );
530 assert( dist != NULL );
531 assert( pred != NULL );
532 assert( ignore[source] == 0 );
533 assert( ignore[target] == 0 );
534
535 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
536
537 /* initialize nodes */
538 for (i = 0; i < G->nodes; ++i)
539 {
540 dist[i] = DIJKSTRA_FARAWAY;
541 order[i] = DIJKSTRA_UNUSED;
542 pred[i] = DIJKSTRA_UNUSED;
543 }
544
545 /* enter source node into heap */
546 entry[0] = source;
547 order[source] = 0;
548 pred[source] = DIJKSTRA_UNUSED;
549 dist[source] = 0;
550
551 ++used;
552
553 /* loop while heap is not empty */
554 while ( used > 0 )
555 {
556 /* get next node */
557 tail = entry[0];
558
559 /* stop if we have found the target node */
560 if ( tail == target )
561 break;
562
563 /* remove node from heap */
564 --used;
565 entry[0] = entry[used];
566 order[entry[0]] = 0;
567 order[tail] = DIJKSTRA_UNUSED;
568
569 dijkstraSiftDown(entry, dist, order, used, 0);
570
571 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
572 assert( entry[used] < G->nodes );
573
574 /* only work on nodes if their distance is less than the cutoff */
575 if ( dist[tail] >= cutoff )
576 continue;
577
578 /* check adjacent nodes */
579 for (e = G->outbeg[tail]; G->head[e] != DIJKSTRA_UNUSED; ++e)
580 {
581 head = G->head[e];
582
583 /* skip ignored nodes */
584 if ( ignore[head] != 0 )
585 continue;
586
587 weight = G->weight[e] + dist[tail];
588
589 /* Can we improve the current shortest path? */
590 if ( dist[head] > weight )
591 {
592 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
593 assert( used < G->nodes );
594 assert( head <= G->nodes );
595
596 pred[head] = tail;
597 dist[head] = weight;
598
599 if ( order[head] == DIJKSTRA_UNUSED )
600 {
601 assert( head < G->nodes );
602
603 entry[used] = head;
604 order[head] = used;
605
606 dijkstraSiftUp(entry, dist, order, used);
607 ++used;
608 }
609 else
610 {
611 dijkstraSiftUp(entry, dist, order, order[head]);
612 }
613 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
614
615 ++iters;
616 }
617 }
618 }
619 assert( dijkstraHeapIsValid(entry, dist, order, used, G->nodes) );
620
621 return iters;
622}
#define NULL
Definition: def.h:267
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
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:190
static void dijkstraSiftUp(unsigned int *entry, const unsigned long long *value, unsigned int *order, unsigned int current)
Definition: dijkstra.c:157
static void dijkstraSiftDown(unsigned int *entry, const unsigned long long *value, unsigned int *order, unsigned int used, unsigned int current)
Definition: dijkstra.c:112
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:290
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:507
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:396
Definitions for Disjkstra's shortest path algorithm.
#define DIJKSTRA_UNUSED
Definition: dijkstra.h:48
#define DIJKSTRA_FARAWAY
Definition: dijkstra.h:47
#define DIJKSTRA_Bool
Definition: dijkstra.h:40
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