Coverage Report

Created: 2025-09-04 06:27

/src/igraph/src/paths/dijkstra.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   igraph library.
3
   Copyright (C) 2005-2025  The igraph development team <igraph@igraph.org>
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 2 of the License, or
8
   (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
*/
18
19
#include "igraph_paths.h"
20
21
#include "igraph_adjlist.h"
22
#include "igraph_interface.h"
23
#include "igraph_memory.h"
24
#include "igraph_nongraph.h"
25
#include "igraph_stack.h"
26
#include "igraph_vector_ptr.h"
27
28
#include "core/indheap.h"
29
#include "core/interruption.h"
30
#include "paths/paths_internal.h"
31
32
#include <string.h>   /* memset */
33
34
igraph_error_t igraph_i_validate_distance_weights(
35
        const igraph_t *graph,
36
        const igraph_vector_t *weights,
37
33.6k
        igraph_bool_t *negative_weights) {
38
39
33.6k
    const igraph_int_t ecount = igraph_ecount(graph);
40
41
33.6k
    *negative_weights = false;
42
43
33.6k
    if (weights) {
44
26.5k
        if (igraph_vector_size(weights) != ecount) {
45
0
            IGRAPH_ERRORF("Edge weight vector length (%" IGRAPH_PRId ") does not match number of edges (%" IGRAPH_PRId ").",
46
0
                          IGRAPH_EINVAL,
47
0
                          igraph_vector_size(weights), ecount);
48
0
        }
49
50
26.5k
        if (ecount > 0) {
51
26.1k
            igraph_real_t min = igraph_vector_min(weights);
52
26.1k
            if (min < 0) {
53
0
                *negative_weights = true;
54
0
            }
55
26.1k
            if (isnan(min)) {
56
0
                IGRAPH_ERROR("Edge weights must not contain NaN values.", IGRAPH_EINVAL);
57
0
            }
58
26.1k
        }
59
26.5k
    }
60
61
33.6k
    return IGRAPH_SUCCESS;
62
33.6k
}
63
64
/**
65
 * \function igraph_distances_dijkstra_cutoff
66
 * \brief Weighted shortest path lengths between vertices, with cutoff.
67
 *
68
 * This function is similar to \ref igraph_distances_dijkstra(), but
69
 * paths longer than \p cutoff will not be considered.
70
 *
71
 * \param graph The input graph, can be directed.
72
 * \param res The result, a matrix. A pointer to an initialized matrix
73
 *    should be passed here. The matrix will be resized as needed.
74
 *    Each row contains the distances from a single source, to the
75
 *    vertices given in the \p to argument.
76
 *    Vertices that are not reachable within distance \p cutoff will
77
 *    be assigned distance \c IGRAPH_INFINITY.
78
 * \param from The source vertices.
79
 * \param to The target vertices. It is not allowed to include a
80
 *    vertex twice or more.
81
 * \param weights The edge weights. All edge weights must be
82
 *    non-negative for Dijkstra's algorithm to work. Additionally, no
83
 *    edge weight may be NaN. If either case does not hold, an error
84
 *    is returned. If this is a null pointer, then the unweighted
85
 *    version, \ref igraph_distances() is called. Edges with positive infinite
86
 *    weights are ignored.
87
 * \param mode For directed graphs; whether to follow paths along edge
88
 *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
89
 *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored
90
 *    for undirected graphs.
91
 * \param cutoff The maximal length of paths that will be considered.
92
 *    When the distance of two vertices is greater than this value,
93
 *    it will be returned as \c IGRAPH_INFINITY. Negative cutoffs and
94
 *    \ref IGRAPH_UNLIMITED are treated as infinity.
95
 * \return Error code.
96
 *
97
 * Time complexity: at most O(s |E| log|V| + |V|), where |V| is the number of
98
 * vertices, |E| the number of edges and s the number of sources. The
99
 * \p cutoff parameter will limit the number of edges traversed from each
100
 * source vertex, which reduces the computation time.
101
 *
102
 * \sa \ref igraph_distances_cutoff() for a (slightly) faster unweighted
103
 * version.
104
 *
105
 * \example examples/simple/distances.c
106
 */
107
igraph_error_t igraph_distances_dijkstra_cutoff(
108
        const igraph_t *graph,
109
        igraph_matrix_t *res,
110
        const igraph_vs_t from,
111
        const igraph_vs_t to,
112
        const igraph_vector_t *weights,
113
        igraph_neimode_t mode,
114
3.20k
        igraph_real_t cutoff) {
115
116
3.20k
    igraph_bool_t negative_weights;
117
3.20k
    IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights));
118
3.20k
    if (negative_weights) {
119
0
        IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.",
120
0
                      IGRAPH_EINVAL,
121
0
                      igraph_vector_min(weights));
122
0
    }
123
3.20k
    return igraph_i_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, cutoff);
124
3.20k
}
125
126
127
igraph_error_t igraph_i_distances_dijkstra_cutoff(const igraph_t *graph,
128
                                   igraph_matrix_t *res,
129
                                   const igraph_vs_t from,
130
                                   const igraph_vs_t to,
131
                                   const igraph_vector_t *weights,
132
                                   igraph_neimode_t mode,
133
3.20k
                                   igraph_real_t cutoff) {
134
135
    /* Implementation details. This is the basic Dijkstra algorithm,
136
       with a binary heap. The heap is indexed, i.e. it stores not only
137
       the distances, but also which vertex they belong to.
138
139
       From now on we use a 2-way heap, so the distances can be queried
140
       directly from the heap.
141
142
       Tricks:
143
       - The opposite of the distance is stored in the heap, as it is a
144
         maximum heap and we need a minimum heap.
145
    */
146
147
3.20k
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
148
3.20k
    igraph_2wheap_t Q;
149
3.20k
    igraph_vit_t fromvit, tovit;
150
3.20k
    igraph_int_t no_of_from, no_of_to;
151
3.20k
    igraph_lazy_inclist_t inclist;
152
3.20k
    igraph_int_t i, j;
153
3.20k
    igraph_bool_t all_to;
154
3.20k
    igraph_vector_int_t indexv;
155
156
3.20k
    if (!weights) {
157
0
        return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, cutoff);
158
0
    }
159
160
3.20k
    IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
161
3.20k
    IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
162
3.20k
    no_of_from = IGRAPH_VIT_SIZE(fromvit);
163
164
3.20k
    IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
165
3.20k
    IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
166
3.20k
    IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS));
167
3.20k
    IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
168
169
3.20k
    all_to = igraph_vs_is_all(&to);
170
3.20k
    if (all_to) {
171
3.20k
        no_of_to = no_of_nodes;
172
3.20k
    } else {
173
0
        IGRAPH_VECTOR_INT_INIT_FINALLY(&indexv, no_of_nodes);
174
0
        IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
175
0
        IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
176
0
        no_of_to = IGRAPH_VIT_SIZE(tovit);
177
178
        /* We need to check whether the vertices in 'tovit' are unique; this is
179
         * because the inner while loop of the main algorithm updates the
180
         * distance matrix whenever a shorter path is encountered from the
181
         * source vertex 'i' to a target vertex, and we need to be able to
182
         * map a target vertex to its column in the distance matrix. The mapping
183
         * is constructed by the loop below */
184
0
        for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) {
185
0
            igraph_int_t v = IGRAPH_VIT_GET(tovit);
186
0
            if (VECTOR(indexv)[v]) {
187
0
                IGRAPH_ERROR("Target vertex list must not have any duplicates.",
188
0
                             IGRAPH_EINVAL);
189
0
            }
190
0
            VECTOR(indexv)[v] = ++i;
191
0
        }
192
0
    }
193
194
3.20k
    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
195
3.20k
    igraph_matrix_fill(res, IGRAPH_INFINITY);
196
197
3.20k
    for (IGRAPH_VIT_RESET(fromvit), i = 0;
198
6.40k
         !IGRAPH_VIT_END(fromvit);
199
3.20k
         IGRAPH_VIT_NEXT(fromvit), i++) {
200
201
3.20k
        igraph_int_t reached = 0;
202
3.20k
        igraph_int_t source = IGRAPH_VIT_GET(fromvit);
203
204
3.20k
        igraph_2wheap_clear(&Q);
205
206
        /* Many systems distinguish between +0.0 and -0.0.
207
         * Since we store negative distances in the heap,
208
         * we must insert -0.0 in order to get +0.0 as the
209
         * final distance result. */
210
3.20k
        igraph_2wheap_push_with_index(&Q, source, -0.0);
211
212
39.1k
        while (!igraph_2wheap_empty(&Q)) {
213
35.9k
            igraph_int_t minnei = igraph_2wheap_max_index(&Q);
214
35.9k
            igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q);
215
35.9k
            igraph_vector_int_t *neis;
216
35.9k
            igraph_int_t nlen;
217
218
35.9k
            if (cutoff >= 0 && mindist > cutoff) {
219
0
                continue;
220
0
            }
221
222
35.9k
            if (all_to) {
223
35.9k
                MATRIX(*res, i, minnei) = mindist;
224
35.9k
            } else {
225
0
                if (VECTOR(indexv)[minnei]) {
226
0
                    MATRIX(*res, i, VECTOR(indexv)[minnei] - 1) = mindist;
227
0
                    reached++;
228
0
                    if (reached == no_of_to) {
229
0
                        igraph_2wheap_clear(&Q);
230
0
                        break;
231
0
                    }
232
0
                }
233
0
            }
234
235
            /* Now check all neighbors of 'minnei' for a shorter path */
236
35.9k
            neis = igraph_lazy_inclist_get(&inclist, minnei);
237
35.9k
            IGRAPH_CHECK_OOM(neis, "Failed to query incident edges.");
238
35.9k
            nlen = igraph_vector_int_size(neis);
239
114k
            for (j = 0; j < nlen; j++) {
240
78.1k
                igraph_int_t edge = VECTOR(*neis)[j];
241
78.1k
                igraph_real_t weight = VECTOR(*weights)[edge];
242
243
                /* Optimization: do not follow infinite-weight edges. */
244
78.1k
                if (weight == IGRAPH_INFINITY) {
245
0
                    continue;
246
0
                }
247
248
78.1k
                igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei);
249
78.1k
                igraph_real_t altdist = mindist + weight;
250
251
78.1k
                if (! igraph_2wheap_has_elem(&Q, tto)) {
252
                    /* This is the first non-infinite distance */
253
32.7k
                    IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
254
45.4k
                } else if (igraph_2wheap_has_active(&Q, tto)) {
255
6.39k
                    igraph_real_t curdist = -igraph_2wheap_get(&Q, tto);
256
6.39k
                    if (altdist < curdist) {
257
                        /* This is a shorter path */
258
1.63k
                        igraph_2wheap_modify(&Q, tto, -altdist);
259
1.63k
                    }
260
6.39k
                }
261
78.1k
            }
262
263
35.9k
        } /* !igraph_2wheap_empty(&Q) */
264
265
3.20k
    } /* !IGRAPH_VIT_END(fromvit) */
266
267
3.20k
    if (!all_to) {
268
0
        igraph_vit_destroy(&tovit);
269
0
        igraph_vector_int_destroy(&indexv);
270
0
        IGRAPH_FINALLY_CLEAN(2);
271
0
    }
272
273
3.20k
    igraph_lazy_inclist_destroy(&inclist);
274
3.20k
    igraph_2wheap_destroy(&Q);
275
3.20k
    igraph_vit_destroy(&fromvit);
276
3.20k
    IGRAPH_FINALLY_CLEAN(3);
277
278
3.20k
    return IGRAPH_SUCCESS;
279
3.20k
}
280
281
/**
282
 * \function igraph_distances_dijkstra
283
 * \brief Weighted shortest path lengths between vertices.
284
 *
285
 * This function implements Dijkstra's algorithm, which can find
286
 * the weighted shortest path lengths from a source vertex to all
287
 * other vertices. This function allows specifying a set of source
288
 * and target vertices. The algorithm is run independently for each
289
 * source and the results are retained only for the specified targets.
290
 * This implementation uses a binary heap for efficiency.
291
 *
292
 * \param graph The input graph, can be directed.
293
 * \param res The result, a matrix. A pointer to an initialized matrix
294
 *    should be passed here. The matrix will be resized as needed.
295
 *    Each row contains the distances from a single source, to the
296
 *    vertices given in the \p to argument.
297
 *    Unreachable vertices have distance \c IGRAPH_INFINITY.
298
 * \param from The source vertices.
299
 * \param to The target vertices. It is not allowed to include a
300
 *    vertex twice or more.
301
 * \param weights The edge weights. All edge weights must be
302
 *    non-negative for Dijkstra's algorithm to work. Additionally, no
303
 *    edge weight may be NaN. If either case does not hold, an error
304
 *    is returned. If this is a null pointer, then the unweighted
305
 *    version, \ref igraph_distances() is called.
306
 * \param mode For directed graphs; whether to follow paths along edge
307
 *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
308
 *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored
309
 *    for undirected graphs.
310
 * \return Error code.
311
 *
312
 * Time complexity: O(s*|E|log|V|+|V|), where |V| is the number of
313
 * vertices, |E| the number of edges and s the number of sources.
314
 *
315
 * \sa \ref igraph_distances() for a non-algorithm-specific interface
316
 * or \ref igraph_distances_bellman_ford() for a weighted
317
 * variant that works in the presence of negative edge weights (but no
318
 * negative loops)
319
 *
320
 * \example examples/simple/distances.c
321
 */
322
igraph_error_t igraph_distances_dijkstra(
323
        const igraph_t *graph,
324
        igraph_matrix_t *res,
325
        const igraph_vs_t from,
326
        const igraph_vs_t to,
327
        const igraph_vector_t *weights,
328
3.20k
        igraph_neimode_t mode) {
329
330
3.20k
    return igraph_distances_dijkstra_cutoff(graph, res, from, to, weights, mode, -1);
331
3.20k
}
332
333
334
/**
335
 * \ingroup structural
336
 * \function igraph_get_shortest_paths_dijkstra
337
 * \brief Weighted shortest paths from a vertex.
338
 *
339
 * Finds weighted shortest paths from a single source vertex to the specified
340
 * sets of target vertices using Dijkstra's algorithm. If there is more than
341
 * one path with the smallest weight between two vertices, this function gives
342
 * only one of them. To find all such paths, use
343
 * \ref igraph_get_all_shortest_paths_dijkstra().
344
 *
345
 * \param graph The graph object.
346
 * \param vertices The result, the IDs of the vertices along the paths.
347
 *        This is a list of integer vectors where each element is an
348
 *        \ref igraph_vector_int_t object. The list will be resized as needed.
349
 *        Supply a null pointer here if you don't need these vectors.
350
 * \param edges The result, the IDs of the edges along the paths.
351
 *        This is a list of integer vectors where each element is an
352
 *        \ref igraph_vector_int_t object. The list will be resized as needed.
353
 *        Supply a null pointer here if you don't need these vectors.
354
 * \param from The id of the vertex from/to which the geodesics are
355
 *        calculated.
356
 * \param to Vertex sequence with the IDs of the vertices to/from which the
357
 *        shortest paths will be calculated. A vertex might be given multiple
358
 *        times.
359
* \param weights The edge weights. All edge weights must be
360
 *       non-negative for Dijkstra's algorithm to work. Additionally, no
361
 *       edge weight may be NaN. If either case does not hold, an error
362
 *       is returned. If this is a null pointer, then the unweighted
363
 *       version, \ref igraph_get_shortest_paths() is called.
364
 * \param mode The type of shortest paths to be use for the
365
 *        calculation in directed graphs. Possible values:
366
 *        \clist
367
 *        \cli IGRAPH_OUT
368
 *          the outgoing paths are calculated.
369
 *        \cli IGRAPH_IN
370
 *          the incoming paths are calculated.
371
 *        \cli IGRAPH_ALL
372
 *          the directed graph is considered as an
373
 *          undirected one for the computation.
374
 *        \endclist
375
 * \param parents A pointer to an initialized igraph vector or null.
376
 *        If not null, a vector containing the parent of each vertex in
377
 *        the single source shortest path tree is returned here. The
378
 *        parent of vertex i in the tree is the vertex from which vertex i
379
 *        was reached. The parent of the start vertex (in the \c from
380
 *        argument) is -1. If the parent is -2, it means
381
 *        that the given vertex was not reached from the source during the
382
 *        search. Note that the search terminates if all the vertices in
383
 *        \c to are reached.
384
 * \param inbound_edges A pointer to an initialized igraph vector or null.
385
 *        If not null, a vector containing the inbound edge of each vertex in
386
 *        the single source shortest path tree is returned here. The
387
 *        inbound edge of vertex i in the tree is the edge via which vertex i
388
 *        was reached. The start vertex and vertices that were not reached
389
 *        during the search will have -1 in the corresponding entry of the
390
 *        vector. Note that the search terminates if all the vertices in
391
 *        \c to are reached.
392
 * \return Error code:
393
 *        \clist
394
 *        \cli IGRAPH_ENOMEM
395
 *           not enough memory for temporary data.
396
 *        \cli IGRAPH_EINVVID
397
 *           \p from is invalid vertex ID
398
 *        \cli IGRAPH_EINVMODE
399
 *           invalid mode argument.
400
 *        \endclist
401
 *
402
 * Time complexity: O(|E|log|V|+|V|), where |V| is the number of
403
 * vertices and |E| is the number of edges
404
 *
405
 * \sa \ref igraph_distances_dijkstra() if you only need the path lengths but
406
 * not the paths themselves; \ref igraph_get_all_shortest_paths_dijkstra() to
407
 * find all shortest paths between (source, target) pairs;
408
 * \ref igraph_get_shortest_paths() for a non-algorithm-specific interface.
409
 *
410
 * \example examples/simple/igraph_get_shortest_paths_dijkstra.c
411
 */
412
igraph_error_t igraph_get_shortest_paths_dijkstra(
413
        const igraph_t *graph,
414
        igraph_vector_int_list_t *vertices,
415
        igraph_vector_int_list_t *edges,
416
        igraph_int_t from,
417
        igraph_vs_t to,
418
        const igraph_vector_t *weights,
419
        igraph_neimode_t mode,
420
        igraph_vector_int_t *parents,
421
20.1k
        igraph_vector_int_t *inbound_edges) {
422
423
20.1k
    igraph_bool_t negative_weights;
424
20.1k
    IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights));
425
20.1k
    if (negative_weights) {
426
0
        IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.",
427
0
                      IGRAPH_EINVAL,
428
0
                      igraph_vector_min(weights));
429
0
    }
430
20.1k
    return igraph_i_get_shortest_paths_dijkstra(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges);
431
20.1k
}
432
433
434
igraph_error_t igraph_i_get_shortest_paths_dijkstra(const igraph_t *graph,
435
                                                  igraph_vector_int_list_t *vertices,
436
                                                  igraph_vector_int_list_t *edges,
437
                                                  igraph_int_t from,
438
                                                  igraph_vs_t to,
439
                                                  const igraph_vector_t *weights,
440
                                                  igraph_neimode_t mode,
441
                                                  igraph_vector_int_t *parents,
442
20.1k
                                                  igraph_vector_int_t *inbound_edges) {
443
    /* Implementation details. This is the basic Dijkstra algorithm,
444
       with a binary heap. The heap is indexed, i.e. it stores not only
445
       the distances, but also which vertex they belong to. The other
446
       mapping, i.e. getting the distance for a vertex is not in the
447
       heap (that would by the double-indexed heap), but in the result
448
       matrix.
449
450
       Dirty tricks:
451
       - the opposite of the distance is stored in the heap, as it is a
452
         maximum heap and we need a minimum heap.
453
       - we don't use IGRAPH_INFINITY in the distance vector during the
454
         computation, as isfinite() might involve a function call
455
         and we want to spare that. So we store distance+1.0 instead of
456
         distance, and zero denotes infinity.
457
       - `parent_eids' assigns the inbound edge IDs of all vertices in the
458
         shortest path tree to the vertices. In this implementation, the
459
         edge ID + 1 is stored, zero means unreachable vertices.
460
    */
461
462
20.1k
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
463
20.1k
    igraph_vit_t vit;
464
20.1k
    igraph_2wheap_t Q;
465
20.1k
    igraph_lazy_inclist_t inclist;
466
20.1k
    igraph_vector_t dists;
467
20.1k
    igraph_int_t *parent_eids;
468
20.1k
    igraph_bool_t *is_target;
469
20.1k
    igraph_int_t i, to_reach;
470
471
20.1k
    if (!weights) {
472
0
        return igraph_i_get_shortest_paths_unweighted(graph, vertices, edges, from, to, mode, parents, inbound_edges);
473
0
    }
474
475
20.1k
    if (from < 0 || from >= no_of_nodes) {
476
0
        IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID);
477
0
    }
478
479
20.1k
    IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
480
20.1k
    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
481
482
20.1k
    if (vertices) {
483
0
        IGRAPH_CHECK(igraph_vector_int_list_resize(vertices, IGRAPH_VIT_SIZE(vit)));
484
0
    }
485
20.1k
    if (edges) {
486
20.1k
        IGRAPH_CHECK(igraph_vector_int_list_resize(edges, IGRAPH_VIT_SIZE(vit)));
487
20.1k
    }
488
489
20.1k
    IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
490
20.1k
    IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
491
20.1k
    IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS));
492
20.1k
    IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
493
494
20.1k
    IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
495
20.1k
    igraph_vector_fill(&dists, -1.0);
496
497
20.1k
    parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t);
498
20.1k
    IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest paths with Dijkstra's algorithm.");
499
20.1k
    IGRAPH_FINALLY(igraph_free, parent_eids);
500
501
20.1k
    is_target = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
502
20.1k
    IGRAPH_CHECK_OOM(is_target, "Insufficient memory for shortest paths with Dijkstra's algorithm.");
503
20.1k
    IGRAPH_FINALLY(igraph_free, is_target);
504
505
    /* Mark the vertices we need to reach */
506
20.1k
    to_reach = IGRAPH_VIT_SIZE(vit);
507
40.3k
    for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
508
20.1k
        if (!is_target[ IGRAPH_VIT_GET(vit) ]) {
509
20.1k
            is_target[ IGRAPH_VIT_GET(vit) ] = true;
510
20.1k
        } else {
511
0
            to_reach--;       /* this node was given multiple times */
512
0
        }
513
20.1k
    }
514
515
20.1k
    VECTOR(dists)[from] = 0.0;  /* zero distance */
516
20.1k
    parent_eids[from] = 0;
517
20.1k
    igraph_2wheap_push_with_index(&Q, from, 0);
518
519
468k
    while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
520
448k
        igraph_int_t nlen, minnei = igraph_2wheap_max_index(&Q);
521
448k
        igraph_real_t mindist = -igraph_2wheap_delete_max(&Q);
522
448k
        igraph_vector_int_t *neis;
523
524
448k
        IGRAPH_ALLOW_INTERRUPTION();
525
526
448k
        if (is_target[minnei]) {
527
19.1k
            is_target[minnei] = false;
528
19.1k
            to_reach--;
529
19.1k
        }
530
531
        /* Now check all neighbors of 'minnei' for a shorter path */
532
448k
        neis = igraph_lazy_inclist_get(&inclist, minnei);
533
448k
        IGRAPH_CHECK_OOM(neis, "Failed to query incident edges.");
534
448k
        nlen = igraph_vector_int_size(neis);
535
1.06M
        for (i = 0; i < nlen; i++) {
536
612k
            igraph_int_t edge = VECTOR(*neis)[i];
537
612k
            igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei);
538
612k
            igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
539
612k
            igraph_real_t curdist = VECTOR(dists)[tto];
540
612k
            if (curdist < 0) {
541
                /* This is the first finite distance */
542
447k
                VECTOR(dists)[tto] = altdist;
543
447k
                parent_eids[tto] = edge + 1;
544
447k
                IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
545
447k
            } else if (altdist < curdist) {
546
                /* This is a shorter path */
547
15.8k
                VECTOR(dists)[tto] = altdist;
548
15.8k
                parent_eids[tto] = edge + 1;
549
15.8k
                igraph_2wheap_modify(&Q, tto, -altdist);
550
15.8k
            }
551
612k
        }
552
448k
    } /* !igraph_2wheap_empty(&Q) */
553
554
20.1k
    if (to_reach > 0) {
555
992
        IGRAPH_WARNING("Couldn't reach some vertices.");
556
992
    }
557
558
    /* Create `parents' if needed */
559
20.1k
    if (parents) {
560
0
        IGRAPH_CHECK(igraph_vector_int_resize(parents, no_of_nodes));
561
562
0
        for (i = 0; i < no_of_nodes; i++) {
563
0
            if (i == from) {
564
                /* i is the start vertex */
565
0
                VECTOR(*parents)[i] = -1;
566
0
            } else if (parent_eids[i] <= 0) {
567
                /* i was not reached */
568
0
                VECTOR(*parents)[i] = -2;
569
0
            } else {
570
                /* i was reached via the edge with ID = parent_eids[i] - 1 */
571
0
                VECTOR(*parents)[i] = IGRAPH_OTHER(graph, parent_eids[i] - 1, i);
572
0
            }
573
0
        }
574
0
    }
575
576
    /* Create `inbound_edges' if needed */
577
20.1k
    if (inbound_edges) {
578
0
        IGRAPH_CHECK(igraph_vector_int_resize(inbound_edges, no_of_nodes));
579
580
0
        for (i = 0; i < no_of_nodes; i++) {
581
0
            if (parent_eids[i] <= 0) {
582
                /* i was not reached */
583
0
                VECTOR(*inbound_edges)[i] = -1;
584
0
            } else {
585
                /* i was reached via the edge with ID = parent_eids[i] - 1 */
586
0
                VECTOR(*inbound_edges)[i] = parent_eids[i] - 1;
587
0
            }
588
0
        }
589
0
    }
590
591
    /* Reconstruct the shortest paths based on vertex and/or edge IDs */
592
20.1k
    if (vertices || edges) {
593
40.3k
        for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
594
20.1k
            igraph_int_t node = IGRAPH_VIT_GET(vit);
595
20.1k
            igraph_int_t size, act, edge;
596
20.1k
            igraph_vector_int_t *vvec = 0, *evec = 0;
597
20.1k
            if (vertices) {
598
0
                vvec = igraph_vector_int_list_get_ptr(vertices, i);
599
0
                igraph_vector_int_clear(vvec);
600
0
            }
601
20.1k
            if (edges) {
602
20.1k
                evec = igraph_vector_int_list_get_ptr(edges, i);
603
20.1k
                igraph_vector_int_clear(evec);
604
20.1k
            }
605
606
20.1k
            IGRAPH_ALLOW_INTERRUPTION();
607
608
20.1k
            size = 0;
609
20.1k
            act = node;
610
418k
            while (parent_eids[act]) {
611
397k
                size++;
612
397k
                edge = parent_eids[act] - 1;
613
397k
                act = IGRAPH_OTHER(graph, edge, act);
614
397k
            }
615
20.1k
            if (vvec && (size > 0 || node == from)) {
616
0
                IGRAPH_CHECK(igraph_vector_int_resize(vvec, size + 1));
617
0
                VECTOR(*vvec)[size] = node;
618
0
            }
619
20.1k
            if (evec) {
620
20.1k
                IGRAPH_CHECK(igraph_vector_int_resize(evec, size));
621
20.1k
            }
622
20.1k
            act = node;
623
418k
            while (parent_eids[act]) {
624
397k
                edge = parent_eids[act] - 1;
625
397k
                act = IGRAPH_OTHER(graph, edge, act);
626
397k
                size--;
627
397k
                if (vvec) {
628
0
                    VECTOR(*vvec)[size] = act;
629
0
                }
630
397k
                if (evec) {
631
397k
                    VECTOR(*evec)[size] = edge;
632
397k
                }
633
397k
            }
634
20.1k
        }
635
20.1k
    }
636
637
20.1k
    igraph_lazy_inclist_destroy(&inclist);
638
20.1k
    igraph_2wheap_destroy(&Q);
639
20.1k
    igraph_vector_destroy(&dists);
640
20.1k
    IGRAPH_FREE(is_target);
641
20.1k
    IGRAPH_FREE(parent_eids);
642
20.1k
    igraph_vit_destroy(&vit);
643
20.1k
    IGRAPH_FINALLY_CLEAN(6);
644
645
20.1k
    return IGRAPH_SUCCESS;
646
20.1k
}
647
648
/**
649
 * \function igraph_get_shortest_path_dijkstra
650
 * \brief Weighted shortest path from one vertex to another one (Dijkstra).
651
 *
652
 * Finds a weighted shortest path from a single source vertex to
653
 * a single target, using Dijkstra's algorithm. If more than one
654
 * shortest path exists, an arbitrary one is returned.
655
 *
656
 * </para><para>
657
 * This function is a special case (and a wrapper) to
658
 * \ref igraph_get_shortest_paths_dijkstra().
659
 *
660
 * \param graph The input graph, it can be directed or undirected.
661
 * \param vertices Pointer to an initialized vector or a null
662
 *        pointer. If not a null pointer, then the vertex IDs along
663
 *        the path are stored here, including the source and target
664
 *        vertices.
665
 * \param edges Pointer to an initialized vector or a null
666
 *        pointer. If not a null pointer, then the edge IDs along the
667
 *        path are stored here.
668
 * \param from The ID of the source vertex.
669
 * \param to The ID of the target vertex.
670
 * \param weights The edge weights. All edge weights must be
671
 *       non-negative for Dijkstra's algorithm to work. Additionally, no
672
 *       edge weight may be NaN. If either case does not hold, an error
673
 *       is returned. If this is a null pointer, then the unweighted
674
 *       version, \ref igraph_get_shortest_paths() is called.
675
 * \param mode A constant specifying how edge directions are
676
 *        considered in directed graphs. \c IGRAPH_OUT follows edge
677
 *        directions, \c IGRAPH_IN follows the opposite directions,
678
 *        and \c IGRAPH_ALL ignores edge directions. This argument is
679
 *        ignored for undirected graphs.
680
 * \return Error code.
681
 *
682
 * Time complexity: O(|E|log|V|+|V|), |V| is the number of vertices,
683
 * |E| is the number of edges in the graph.
684
 *
685
 * \sa \ref igraph_get_shortest_paths_dijkstra() for the version with
686
 * more target vertices.
687
 */
688
689
igraph_error_t igraph_get_shortest_path_dijkstra(const igraph_t *graph,
690
                                      igraph_vector_int_t *vertices,
691
                                      igraph_vector_int_t *edges,
692
                                      igraph_int_t from,
693
                                      igraph_int_t to,
694
                                      const igraph_vector_t *weights,
695
20.1k
                                      igraph_neimode_t mode) {
696
697
20.1k
    igraph_vector_int_list_t vertices2, *vp = &vertices2;
698
20.1k
    igraph_vector_int_list_t edges2, *ep = &edges2;
699
700
20.1k
    if (vertices) {
701
0
        IGRAPH_CHECK(igraph_vector_int_list_init(&vertices2, 1));
702
0
        IGRAPH_FINALLY(igraph_vector_int_list_destroy, &vertices2);
703
20.1k
    } else {
704
20.1k
        vp = NULL;
705
20.1k
    }
706
20.1k
    if (edges) {
707
20.1k
        IGRAPH_CHECK(igraph_vector_int_list_init(&edges2, 1));
708
20.1k
        IGRAPH_FINALLY(igraph_vector_int_list_destroy, &edges2);
709
20.1k
    } else {
710
0
        ep = NULL;
711
0
    }
712
713
20.1k
    IGRAPH_CHECK(igraph_get_shortest_paths_dijkstra(graph, vp, ep,
714
20.1k
                 from, igraph_vss_1(to),
715
20.1k
                 weights, mode, NULL, NULL));
716
717
    /* We use the constant time vector_swap() instead of the linear-time vector_update() to move the
718
       result to the output parameter. */
719
20.1k
    if (edges) {
720
20.1k
        igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0));
721
20.1k
        igraph_vector_int_list_destroy(&edges2);
722
20.1k
        IGRAPH_FINALLY_CLEAN(1);
723
20.1k
    }
724
20.1k
    if (vertices) {
725
0
        igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0));
726
0
        igraph_vector_int_list_destroy(&vertices2);
727
0
        IGRAPH_FINALLY_CLEAN(1);
728
0
    }
729
730
20.1k
    return IGRAPH_SUCCESS;
731
20.1k
}
732
733
/**
734
 * \ingroup structural
735
 * \function igraph_get_all_shortest_paths_dijkstra
736
 * \brief All weighted shortest paths (geodesics) from a vertex.
737
 *
738
 * \param graph The graph object.
739
 * \param vertices Pointer to an initialized integer vector list or NULL.
740
 *   If not NULL, then each vector object contains the vertices along a
741
 *   shortest path from \p from to another vertex. The vectors are
742
 *   ordered according to their target vertex: first the shortest
743
 *   paths to vertex 0, then to vertex 1, etc. No data is included
744
 *   for unreachable vertices.
745
 * \param edges Pointer to an initialized integer vector list or NULL. If
746
 *   not NULL, then each vector object contains the edges along a
747
 *   shortest path from \p from to another vertex. The vectors are
748
 *   ordered according to their target vertex: first the shortest
749
 *   paths to vertex 0, then to vertex 1, etc. No data is included for
750
 *   unreachable vertices.
751
 * \param nrgeo Pointer to an initialized igraph_vector_int_t object or
752
 *   NULL. If not NULL the number of shortest paths from \p from are
753
 *   stored here for every vertex in the graph. Note that the values
754
 *   will be accurate only for those vertices that are in the target
755
 *   vertex sequence (see \p to), since the search terminates as soon
756
 *   as all the target vertices have been found.
757
 * \param from The id of the vertex from/to which the geodesics are
758
 *        calculated.
759
 * \param to Vertex sequence with the IDs of the vertices to/from which the
760
 *        shortest paths will be calculated. A vertex might be given multiple
761
 *        times.
762
 * \param weights The edge weights. All edge weights must be
763
 *       non-negative for Dijkstra's algorithm to work. Additionally, no
764
 *       edge weight may be NaN. If either case does not hold, an error
765
 *       is returned. If this is a null pointer, then the unweighted
766
 *       version, \ref igraph_get_all_shortest_paths() is called.
767
 * \param mode The type of shortest paths to be use for the
768
 *        calculation in directed graphs. Possible values:
769
 *        \clist
770
 *        \cli IGRAPH_OUT
771
 *          the outgoing paths are calculated.
772
 *        \cli IGRAPH_IN
773
 *          the incoming paths are calculated.
774
 *        \cli IGRAPH_ALL
775
 *          the directed graph is considered as an
776
 *          undirected one for the computation.
777
 *        \endclist
778
 * \return Error code:
779
 *        \clist
780
 *        \cli IGRAPH_ENOMEM
781
 *           not enough memory for temporary data.
782
 *        \cli IGRAPH_EINVVID
783
 *           \p from is an invalid vertex ID
784
 *        \cli IGRAPH_EINVMODE
785
 *           invalid mode argument.
786
 *        \endclist
787
 *
788
 * Time complexity: O(|E|log|V|+|V|), where |V| is the number of
789
 * vertices and |E| is the number of edges
790
 *
791
 * \sa \ref igraph_distances_dijkstra() if you only need the path
792
 * lengths but not the paths themselves, \ref igraph_get_all_shortest_paths()
793
 * if all edge weights are equal.
794
 *
795
 * \example examples/simple/igraph_get_all_shortest_paths_dijkstra.c
796
 */
797
igraph_error_t igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph,
798
        igraph_vector_int_list_t *vertices,
799
        igraph_vector_int_list_t *edges,
800
        igraph_vector_int_t *nrgeo,
801
        igraph_int_t from, igraph_vs_t to,
802
        const igraph_vector_t *weights,
803
0
        igraph_neimode_t mode) {
804
805
    /* Implementation details: see igraph_get_shortest_paths_dijkstra(),
806
     * it's basically the same. */
807
808
0
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
809
0
    igraph_vit_t vit;
810
0
    igraph_2wheap_t Q;
811
0
    igraph_lazy_inclist_t inclist;
812
0
    igraph_vector_t dists;
813
0
    igraph_vector_int_t index;
814
0
    igraph_vector_int_t order;
815
0
    igraph_vector_ptr_t parents, parents_edge;
816
0
    igraph_bool_t negative_weights;
817
818
0
    unsigned char *is_target; /* uses more than two discrete values, can't be 'bool' */
819
0
    igraph_int_t i, n, to_reach;
820
0
    igraph_bool_t free_vertices = false;
821
0
    int cmp_result;
822
0
    const double eps = IGRAPH_SHORTEST_PATH_EPSILON;
823
824
0
    if (!weights) {
825
0
        return igraph_i_get_all_shortest_paths_unweighted(graph, vertices, edges, nrgeo, from, to, mode);
826
0
    }
827
828
0
    if (from < 0 || from >= no_of_nodes) {
829
0
        IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID);
830
0
    }
831
832
0
    IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights));
833
0
    if (negative_weights) {
834
0
        IGRAPH_ERRORF("Edge weights must not be negative when using Dijkstra's algorithm, got %g.",
835
0
                      IGRAPH_EINVAL,
836
0
                      igraph_vector_min(weights));
837
0
    }
838
839
0
    if (vertices == NULL && nrgeo == NULL && edges == NULL) {
840
0
        return IGRAPH_SUCCESS;
841
0
    }
842
843
    /* parents stores a vector for each vertex, listing the parent vertices
844
     * of each vertex in the traversal. Right now we do not use an
845
     * igraph_vector_int_list_t because that would pre-initialize vectors
846
     * for all the nodes even if the traversal would involve only a small part
847
     * of the graph */
848
0
    IGRAPH_CHECK(igraph_vector_ptr_init(&parents, no_of_nodes));
849
0
    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &parents);
850
0
    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&parents, igraph_vector_destroy);
851
852
    /* parents_edge stores a vector for each vertex, listing the parent edges
853
     * of each vertex in the traversal */
854
0
    IGRAPH_CHECK(igraph_vector_ptr_init(&parents_edge, no_of_nodes));
855
0
    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &parents_edge);
856
0
    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&parents_edge, igraph_vector_destroy);
857
858
0
    for (i = 0; i < no_of_nodes; i++) {
859
0
        igraph_vector_int_t *parent_vec, *parent_edge_vec;
860
861
0
        parent_vec = IGRAPH_CALLOC(1, igraph_vector_int_t);
862
0
        IGRAPH_CHECK_OOM(parent_vec, "Insufficient memory for all shortest paths with Dijkstra's algorithm.");
863
0
        IGRAPH_FINALLY(igraph_free, parent_vec);
864
0
        IGRAPH_CHECK(igraph_vector_int_init(parent_vec, 0));
865
0
        VECTOR(parents)[i] = parent_vec;
866
0
        IGRAPH_FINALLY_CLEAN(1);
867
868
0
        parent_edge_vec = IGRAPH_CALLOC(1, igraph_vector_int_t);
869
0
        IGRAPH_CHECK_OOM(parent_edge_vec, "Insufficient memory for all shortest paths with Dijkstra's algorithm.");
870
0
        IGRAPH_FINALLY(igraph_free, parent_edge_vec);
871
0
        IGRAPH_CHECK(igraph_vector_int_init(parent_edge_vec, 0));
872
0
        VECTOR(parents_edge)[i] = parent_edge_vec;
873
0
        IGRAPH_FINALLY_CLEAN(1);
874
0
    }
875
876
    /* distance of each vertex from the root */
877
0
    IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
878
0
    igraph_vector_fill(&dists, -1.0);
879
880
    /* order lists the order of vertices in which they were found during
881
     * the traversal */
882
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&order, 0);
883
884
    /* boolean array to mark whether a given vertex is a target or not */
885
0
    is_target = IGRAPH_CALLOC(no_of_nodes, unsigned char);
886
0
    IGRAPH_CHECK_OOM(is_target, "Insufficient memory for all shortest paths with Dijkstra's algorithm.");
887
0
    IGRAPH_FINALLY(igraph_free, is_target);
888
889
    /* two-way heap storing vertices and distances */
890
0
    IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
891
0
    IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
892
893
    /* lazy adjacency edge list to query neighbours efficiently */
894
0
    IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS));
895
0
    IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
896
897
    /* Mark the vertices we need to reach */
898
0
    IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
899
0
    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
900
0
    to_reach = IGRAPH_VIT_SIZE(vit);
901
0
    for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
902
0
        if (!is_target[ IGRAPH_VIT_GET(vit) ]) {
903
0
            is_target[ IGRAPH_VIT_GET(vit) ] = 1;
904
0
        } else {
905
0
            to_reach--; /* this node was given multiple times */
906
0
        }
907
0
    }
908
0
    igraph_vit_destroy(&vit);
909
0
    IGRAPH_FINALLY_CLEAN(1);
910
911
0
    VECTOR(dists)[from] = 0.0; /* zero distance */
912
0
    igraph_2wheap_push_with_index(&Q, from, 0.0);
913
914
0
    while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
915
0
        igraph_int_t nlen, minnei = igraph_2wheap_max_index(&Q);
916
0
        igraph_real_t mindist = -igraph_2wheap_delete_max(&Q);
917
0
        igraph_vector_int_t *neis;
918
919
0
        IGRAPH_ALLOW_INTERRUPTION();
920
921
0
        if (is_target[minnei]) {
922
0
            is_target[minnei] = 0;
923
0
            to_reach--;
924
0
        }
925
926
        /* Mark that we have reached this vertex */
927
0
        IGRAPH_CHECK(igraph_vector_int_push_back(&order, minnei));
928
929
        /* Now check all neighbors of 'minnei' for a shorter path */
930
0
        neis = igraph_lazy_inclist_get(&inclist, minnei);
931
0
        IGRAPH_CHECK_OOM(neis, "Failed to query incident edges.");
932
0
        nlen = igraph_vector_int_size(neis);
933
0
        for (i = 0; i < nlen; i++) {
934
0
            igraph_int_t edge = VECTOR(*neis)[i];
935
0
            igraph_int_t tto = IGRAPH_OTHER(graph, edge, minnei);
936
0
            igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
937
0
            igraph_real_t curdist = VECTOR(dists)[tto];
938
0
            igraph_vector_int_t *parent_vec, *parent_edge_vec;
939
940
0
            cmp_result = igraph_cmp_epsilon(curdist, altdist, eps);
941
0
            if (curdist < 0) {
942
                /* This is the first non-infinite distance */
943
0
                VECTOR(dists)[tto] = altdist;
944
945
0
                parent_vec = (igraph_vector_int_t*)VECTOR(parents)[tto];
946
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_vec, minnei));
947
0
                parent_edge_vec = (igraph_vector_int_t*)VECTOR(parents_edge)[tto];
948
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_edge_vec, edge));
949
950
0
                IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
951
0
            } else if (cmp_result == 0 /* altdist == curdist */ && VECTOR(*weights)[edge] > 0) {
952
                /* This is an alternative path with exactly the same length.
953
                 * Note that we consider this case only if the edge via which we
954
                 * reached the node has a nonzero weight; otherwise we could create
955
                 * infinite loops in undirected graphs by traversing zero-weight edges
956
                 * back-and-forth */
957
0
                parent_vec = (igraph_vector_int_t*) VECTOR(parents)[tto];
958
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_vec, minnei));
959
0
                parent_edge_vec = (igraph_vector_int_t*) VECTOR(parents_edge)[tto];
960
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_edge_vec, edge));
961
0
            } else if (cmp_result > 0 /* altdist < curdist */) {
962
                /* This is a shorter path */
963
0
                VECTOR(dists)[tto] = altdist;
964
965
0
                parent_vec = (igraph_vector_int_t*)VECTOR(parents)[tto];
966
0
                igraph_vector_int_clear(parent_vec);
967
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_vec, minnei));
968
0
                parent_edge_vec = (igraph_vector_int_t*)VECTOR(parents_edge)[tto];
969
0
                igraph_vector_int_clear(parent_edge_vec);
970
0
                IGRAPH_CHECK(igraph_vector_int_push_back(parent_edge_vec, edge));
971
972
0
                igraph_2wheap_modify(&Q, tto, -altdist);
973
0
            }
974
0
        }
975
0
    } /* !igraph_2wheap_empty(&Q) */
976
977
0
    if (to_reach > 0) {
978
0
        IGRAPH_WARNING("Couldn't reach some of the requested target vertices.");
979
0
    }
980
981
    /* we don't need these anymore */
982
0
    igraph_lazy_inclist_destroy(&inclist);
983
0
    igraph_2wheap_destroy(&Q);
984
0
    IGRAPH_FINALLY_CLEAN(2);
985
986
    /*
987
    printf("Order:\n");
988
    igraph_vector_int_print(&order);
989
990
    printf("Parent vertices:\n");
991
    for (i = 0; i < no_of_nodes; i++) {
992
      if (igraph_vector_int_size(VECTOR(parents)[i]) > 0) {
993
        printf("[%ld]: ", i);
994
        igraph_vector_int_print(VECTOR(parents)[i]);
995
      }
996
    }
997
    */
998
999
0
    if (nrgeo) {
1000
0
        IGRAPH_CHECK(igraph_vector_int_resize(nrgeo, no_of_nodes));
1001
0
        igraph_vector_int_null(nrgeo);
1002
1003
        /* Theoretically, we could calculate nrgeo in parallel with the traversal.
1004
         * However, that way we would have to check whether nrgeo is null or not
1005
         * every time we want to update some element in nrgeo. Since we need the
1006
         * order vector anyway for building the final result, we could just as well
1007
         * build nrgeo here.
1008
         */
1009
0
        VECTOR(*nrgeo)[from] = 1;
1010
0
        n = igraph_vector_int_size(&order);
1011
0
        for (i = 1; i < n; i++) {
1012
0
            igraph_int_t node, j, k;
1013
0
            igraph_vector_int_t *parent_vec;
1014
1015
0
            node = VECTOR(order)[i];
1016
            /* now, take the parent vertices */
1017
0
            parent_vec = (igraph_vector_int_t*)VECTOR(parents)[node];
1018
0
            k = igraph_vector_int_size(parent_vec);
1019
0
            for (j = 0; j < k; j++) {
1020
0
                VECTOR(*nrgeo)[node] += VECTOR(*nrgeo)[VECTOR(*parent_vec)[j]];
1021
0
            }
1022
0
        }
1023
0
    }
1024
1025
0
    if (vertices || edges) {
1026
0
        igraph_vector_int_t *path, *parent_vec, *parent_edge_vec;
1027
0
        igraph_vector_t *paths_index;
1028
0
        igraph_stack_int_t stack;
1029
0
        igraph_int_t j, node;
1030
1031
        /* a shortest path from the starting vertex to vertex i can be
1032
         * obtained by calculating the shortest paths from the "parents"
1033
         * of vertex i in the traversal. Knowing which of the vertices
1034
         * are "targets" (see is_target), we can collect for which other
1035
         * vertices do we need to calculate the shortest paths. We reuse
1036
         * is_target for that; is_target = 0 means that we don't need the
1037
         * vertex, is_target = 1 means that the vertex is a target (hence
1038
         * we need it), is_target = 2 means that the vertex is not a target
1039
         * but it stands between a shortest path between the root and one
1040
         * of the targets
1041
         */
1042
0
        if (igraph_vs_is_all(&to)) {
1043
0
            memset(is_target, 1, sizeof(unsigned char) * (size_t) no_of_nodes);
1044
0
        } else {
1045
0
            memset(is_target, 0, sizeof(unsigned char) * (size_t) no_of_nodes);
1046
1047
0
            IGRAPH_CHECK(igraph_stack_int_init(&stack, 0));
1048
0
            IGRAPH_FINALLY(igraph_stack_int_destroy, &stack);
1049
1050
            /* Add the target vertices to the queue */
1051
0
            IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
1052
0
            IGRAPH_FINALLY(igraph_vit_destroy, &vit);
1053
0
            for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
1054
0
                i = IGRAPH_VIT_GET(vit);
1055
0
                if (!is_target[i]) {
1056
0
                    is_target[i] = 1;
1057
0
                    IGRAPH_CHECK(igraph_stack_int_push(&stack, i));
1058
0
                }
1059
0
            }
1060
0
            igraph_vit_destroy(&vit);
1061
0
            IGRAPH_FINALLY_CLEAN(1);
1062
1063
0
            while (!igraph_stack_int_empty(&stack)) {
1064
                /* For each parent of node i, get its parents */
1065
0
                igraph_int_t el = igraph_stack_int_pop(&stack);
1066
0
                parent_vec = (igraph_vector_int_t*) VECTOR(parents)[el];
1067
0
                i = igraph_vector_int_size(parent_vec);
1068
1069
0
                for (j = 0; j < i; j++) {
1070
                    /* For each parent, check if it's already in the stack.
1071
                     * If not, push it and mark it in is_target */
1072
0
                    n = VECTOR(*parent_vec)[j];
1073
0
                    if (!is_target[n]) {
1074
0
                        is_target[n] = 2;
1075
0
                        IGRAPH_CHECK(igraph_stack_int_push(&stack, n));
1076
0
                    }
1077
0
                }
1078
0
            }
1079
0
            igraph_stack_int_destroy(&stack);
1080
0
            IGRAPH_FINALLY_CLEAN(1);
1081
0
        }
1082
1083
        /* now, reconstruct the shortest paths from the parent list in the
1084
         * order we've found the nodes during the traversal.
1085
         * dists is being re-used as a vector where element i tells the
1086
         * index in vertices where the shortest paths leading to vertex i
1087
         * start, plus one (so that zero means that there are no paths
1088
         * for a given vertex).
1089
         */
1090
0
        paths_index = &dists;
1091
0
        n = igraph_vector_int_size(&order);
1092
0
        igraph_vector_null(paths_index);
1093
1094
0
        if (edges) {
1095
0
            igraph_vector_int_list_clear(edges);
1096
0
        }
1097
1098
0
        if (vertices) {
1099
0
            igraph_vector_int_list_clear(vertices);
1100
0
        } else {
1101
            /* If the 'vertices' vector doesn't exist, then create one, in order
1102
             * for the algorithm to work. */
1103
0
            vertices = IGRAPH_CALLOC(1, igraph_vector_int_list_t);
1104
0
            IGRAPH_CHECK_OOM(vertices, "Insufficient memory for all shortest paths with Dijkstra's algorithm.");
1105
0
            IGRAPH_FINALLY(igraph_free, vertices);
1106
0
            IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(vertices, 0);
1107
0
            free_vertices = true;
1108
0
        }
1109
1110
        /* by definition, the shortest path leading to the starting vertex
1111
         * consists of the vertex itself only */
1112
0
        IGRAPH_CHECK(igraph_vector_int_list_push_back_new(vertices, &path));
1113
0
        IGRAPH_CHECK(igraph_vector_int_push_back(path, from));
1114
1115
0
        if (edges) {
1116
            /* the shortest path from the source to itself is empty */
1117
0
            IGRAPH_CHECK(igraph_vector_int_list_push_back_new(edges, &path));
1118
0
        }
1119
0
        VECTOR(*paths_index)[from] = 1;
1120
1121
0
        for (i = 1; i < n; i++) {
1122
0
            igraph_int_t m, path_count;
1123
0
            igraph_vector_int_t *parent_path, *parent_path_edge;
1124
1125
0
            node = VECTOR(order)[i];
1126
1127
            /* if we don't need the shortest paths for this node (because
1128
             * it is not standing in a shortest path between the source
1129
             * node and any of the target nodes), skip it */
1130
0
            if (!is_target[node]) {
1131
0
                continue;
1132
0
            }
1133
1134
0
            IGRAPH_ALLOW_INTERRUPTION();
1135
1136
            /* we are calculating the shortest paths of node now. */
1137
            /* first, we update the paths_index */
1138
0
            path_count = igraph_vector_int_list_size(vertices);
1139
0
            VECTOR(*paths_index)[node] = path_count + 1;
1140
1141
            /* now, take the parent vertices */
1142
0
            parent_vec = (igraph_vector_int_t*) VECTOR(parents)[node];
1143
0
            parent_edge_vec = (igraph_vector_int_t*) VECTOR(parents_edge)[node];
1144
0
            m = igraph_vector_int_size(parent_vec);
1145
1146
            /*
1147
            printf("Calculating shortest paths to vertex %ld\n", node);
1148
            printf("Parents are: ");
1149
            igraph_vector_print(parent_vec);
1150
            */
1151
1152
0
            for (j = 0; j < m; j++) {
1153
                /* for each parent, copy the shortest paths leading to that parent
1154
                 * and add the current vertex in the end */
1155
0
                igraph_int_t parent_node = VECTOR(*parent_vec)[j];
1156
0
                igraph_int_t parent_edge = VECTOR(*parent_edge_vec)[j];
1157
0
                igraph_int_t parent_path_idx = VECTOR(*paths_index)[parent_node] - 1;
1158
                /*
1159
                printf("  Considering parent: %ld\n", parent_node);
1160
                printf("  Paths to parent start at index %ld in vertices\n", parent_path_idx);
1161
                */
1162
0
                IGRAPH_ASSERT(parent_path_idx >= 0);
1163
0
                for (; parent_path_idx < path_count; parent_path_idx++) {
1164
0
                    parent_path = igraph_vector_int_list_get_ptr(vertices, parent_path_idx);
1165
0
                    if (igraph_vector_int_tail(parent_path) != parent_node) {
1166
0
                        break;
1167
0
                    }
1168
1169
0
                    IGRAPH_CHECK(igraph_vector_int_list_push_back_new(vertices, &path));
1170
1171
                    /* We need to re-read parent_path because the previous push_back_new()
1172
                     * call might have reallocated the entire vector list */
1173
0
                    parent_path = igraph_vector_int_list_get_ptr(vertices, parent_path_idx);
1174
0
                    IGRAPH_CHECK(igraph_vector_int_update(path, parent_path));
1175
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(path, node));
1176
1177
0
                    if (edges) {
1178
0
                        IGRAPH_CHECK(igraph_vector_int_list_push_back_new(edges, &path));
1179
0
                        if (parent_node != from) {
1180
0
                            parent_path_edge = igraph_vector_int_list_get_ptr(edges, parent_path_idx);
1181
0
                            IGRAPH_CHECK(igraph_vector_int_update(path, parent_path_edge));
1182
0
                        }
1183
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(path, parent_edge));
1184
0
                    }
1185
0
                }
1186
0
            }
1187
0
        }
1188
1189
        /* free those paths from the result vector that we won't need */
1190
0
        n = igraph_vector_int_list_size(vertices);
1191
0
        i = 0;
1192
0
        while (i < n) {
1193
0
            igraph_int_t tmp;
1194
0
            path = igraph_vector_int_list_get_ptr(vertices, i);
1195
0
            tmp = igraph_vector_int_tail(path);
1196
0
            if (is_target[tmp] == 1) {
1197
                /* we need this path, keep it */
1198
0
                i++;
1199
0
            } else {
1200
                /* we don't need this path, free it */
1201
0
                igraph_vector_int_list_discard_fast(vertices, i);
1202
0
                if (edges) {
1203
0
                    igraph_vector_int_list_discard_fast(edges, i);
1204
0
                }
1205
0
                n--;
1206
0
            }
1207
0
        }
1208
1209
        /* sort the remaining paths by the target vertices */
1210
0
        IGRAPH_VECTOR_INT_INIT_FINALLY(&index, 0);
1211
0
        igraph_vector_int_list_sort_ind(vertices, &index, igraph_vector_int_colex_cmp);
1212
0
        IGRAPH_CHECK(igraph_vector_int_list_permute(vertices, &index));
1213
0
        if (edges) {
1214
0
            IGRAPH_CHECK(igraph_vector_int_list_permute(edges, &index));
1215
0
        }
1216
0
        igraph_vector_int_destroy(&index);
1217
0
        IGRAPH_FINALLY_CLEAN(1);
1218
0
    }
1219
1220
    /* free the allocated memory */
1221
0
    if (free_vertices) {
1222
0
        igraph_vector_int_list_destroy(vertices);
1223
0
        IGRAPH_FREE(vertices);
1224
0
        IGRAPH_FINALLY_CLEAN(2);
1225
0
    }
1226
1227
0
    igraph_vector_int_destroy(&order);
1228
0
    IGRAPH_FREE(is_target);
1229
0
    igraph_vector_destroy(&dists);
1230
0
    igraph_vector_ptr_destroy_all(&parents);
1231
0
    igraph_vector_ptr_destroy_all(&parents_edge);
1232
0
    IGRAPH_FINALLY_CLEAN(5);
1233
1234
0
    return IGRAPH_SUCCESS;
1235
0
}