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-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
    208 assert( dijkstraGraphIsValid(G) );
    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
    309 assert( dijkstraGraphIsValid(G) );
    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
    416 assert( dijkstraGraphIsValid(G) );
    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
    528 assert( dijkstraGraphIsValid(G) );
    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
    #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