Coverage Report

Created: 2025-10-28 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/paths/bellman_ford.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2005-2025 The igraph development team
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_bitset.h"
23
#include "igraph_dqueue.h"
24
#include "igraph_interface.h"
25
#include "igraph_memory.h"
26
27
#include "core/interruption.h"
28
#include "paths/paths_internal.h"
29
30
/**
31
 * \function igraph_distances_bellman_ford
32
 * \brief Weighted shortest path lengths between vertices, allowing negative weights.
33
 *
34
 * This function implements the Bellman-Ford algorithm to find the weighted
35
 * shortest paths to all vertices from a single source, allowing negative weights.
36
 * It is run independently for the given sources. If there are no negative
37
 * weights, you are better off with \ref igraph_distances_dijkstra() .
38
 *
39
 * \param graph The input graph, can be directed.
40
 * \param res The result, a matrix. A pointer to an initialized matrix
41
 *    should be passed here, the matrix will be resized if needed.
42
 *    Each row contains the distances from a single source, to all
43
 *    vertices in the graph, in the order of vertex IDs. For unreachable
44
 *    vertices the matrix contains \c IGRAPH_INFINITY.
45
 * \param from The source vertices.
46
 * \param to The target vertices.
47
 * \param weights The edge weights. There must not be any cycle in
48
 *    the graph that has a negative total weight (since this would allow
49
 *    us to decrease the weight of any path containing at least a single
50
 *    vertex of this cycle infinitely). Additionally, no edge weight may
51
 *    be NaN. If either case does not hold, an error is returned. If this
52
 *    is a null pointer, then the unweighted version,
53
 *    \ref igraph_distances() is called.
54
 * \param mode For directed graphs; whether to follow paths along edge
55
 *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
56
 *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored
57
 *    for undirected graphs.
58
 * \return Error code.
59
 *
60
 * Time complexity: O(s*|E|*|V|), where |V| is the number of
61
 * vertices, |E| the number of edges and s the number of sources.
62
 *
63
 * \sa \ref igraph_distances() for a non-algorithm-specific interface;
64
 * \ref igraph_distances_dijkstra() if you do not have negative
65
 * edge weights.
66
 *
67
 * \example examples/simple/bellman_ford.c
68
 */
69
igraph_error_t igraph_distances_bellman_ford(
70
        const igraph_t *graph,
71
        igraph_matrix_t *res,
72
        const igraph_vs_t from,
73
        const igraph_vs_t to,
74
        const igraph_vector_t *weights,
75
3.02k
        igraph_neimode_t mode) {
76
77
3.02k
    igraph_bool_t negative_weights;
78
3.02k
    IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights));
79
3.02k
    return igraph_i_distances_bellman_ford(graph, res, from, to, weights, mode);
80
3.02k
}
81
82
igraph_error_t igraph_i_distances_bellman_ford(
83
        const igraph_t *graph,
84
        igraph_matrix_t *res,
85
        const igraph_vs_t from, const igraph_vs_t to,
86
        const igraph_vector_t *weights,
87
3.02k
        igraph_neimode_t mode) {
88
89
3.02k
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
90
3.02k
    igraph_int_t no_of_edges = igraph_ecount(graph);
91
3.02k
    igraph_lazy_inclist_t inclist;
92
3.02k
    igraph_int_t i;
93
3.02k
    igraph_int_t no_of_from, no_of_to;
94
3.02k
    igraph_dqueue_int_t Q;
95
3.02k
    igraph_bitset_t clean_vertices;
96
3.02k
    igraph_vector_int_t num_queued;
97
3.02k
    igraph_vit_t fromvit, tovit;
98
3.02k
    igraph_bool_t all_to;
99
3.02k
    igraph_vector_t dist;
100
3.02k
    int iter = 0;
101
102
    /*
103
       - speedup: a vertex is marked clean if its distance from the source
104
         did not change during the last phase. Neighbors of a clean vertex
105
         are not relaxed again, since it would mean no change in the
106
         shortest path values. Dirty vertices are queued. Negative cycles can
107
         be detected by checking whether a vertex has been queued at least
108
         n times.
109
    */
110
111
3.02k
    if (!weights || no_of_edges == 0) {
112
142
        return igraph_i_distances_unweighted_cutoff(graph, res, from, to, mode, -1);
113
142
    }
114
115
2.88k
    IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
116
2.88k
    IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
117
2.88k
    no_of_from = IGRAPH_VIT_SIZE(fromvit);
118
119
2.88k
    IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, no_of_nodes);
120
2.88k
    IGRAPH_BITSET_INIT_FINALLY(&clean_vertices, no_of_nodes);
121
2.88k
    IGRAPH_VECTOR_INT_INIT_FINALLY(&num_queued, no_of_nodes);
122
2.88k
    IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS));
123
2.88k
    IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
124
125
2.88k
    all_to = igraph_vs_is_all(&to);
126
2.88k
    if (all_to) {
127
2.88k
        no_of_to = no_of_nodes;
128
2.88k
    } else {
129
0
        IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
130
0
        IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
131
0
        no_of_to = IGRAPH_VIT_SIZE(tovit);
132
133
        /* No need to check here whether the vertices in 'to' are unique because
134
         * the loop below uses a temporary distance vector that is then copied
135
         * into the result matrix at the end of the outer loop iteration, and
136
         * this is safe even if 'to' contains the same vertex multiple times */
137
0
    }
138
139
2.88k
    IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
140
2.88k
    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
141
142
2.88k
    for (IGRAPH_VIT_RESET(fromvit), i = 0;
143
5.77k
         !IGRAPH_VIT_END(fromvit);
144
2.88k
         IGRAPH_VIT_NEXT(fromvit), i++) {
145
2.88k
        igraph_int_t source = IGRAPH_VIT_GET(fromvit);
146
147
2.88k
        igraph_vector_fill(&dist, IGRAPH_INFINITY);
148
2.88k
        VECTOR(dist)[source] = 0;
149
2.88k
        igraph_bitset_null(&clean_vertices);
150
2.88k
        igraph_vector_int_null(&num_queued);
151
152
        /* Fill the queue with vertices to be checked */
153
565k
        for (igraph_int_t j = 0; j < no_of_nodes; j++) {
154
562k
            IGRAPH_CHECK(igraph_dqueue_int_push(&Q, j));
155
562k
        }
156
157
590k
        while (!igraph_dqueue_int_empty(&Q)) {
158
587k
            IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 13);
159
160
587k
            igraph_int_t j = igraph_dqueue_int_pop(&Q);
161
587k
            IGRAPH_BIT_SET(clean_vertices, j);
162
587k
            VECTOR(num_queued)[j] += 1;
163
587k
            if (VECTOR(num_queued)[j] > no_of_nodes) {
164
0
                IGRAPH_ERROR("Negative cycle in graph while calculating distances with Bellman-Ford algorithm.",
165
0
                             IGRAPH_ENEGCYCLE);
166
0
            }
167
168
            /* If we cannot get to j in finite time yet, there is no need to relax
169
             * its edges */
170
587k
            if (VECTOR(dist)[j] == IGRAPH_INFINITY) {
171
548k
                continue;
172
548k
            }
173
174
39.4k
            igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, j);
175
39.4k
            IGRAPH_CHECK_OOM(neis, "Failed to query incident edges.");
176
177
39.4k
            igraph_int_t nlen = igraph_vector_int_size(neis);
178
125k
            for (igraph_int_t k = 0; k < nlen; k++) {
179
85.9k
                igraph_int_t nei = VECTOR(*neis)[k];
180
85.9k
                igraph_int_t target = IGRAPH_OTHER(graph, nei, j);
181
85.9k
                igraph_real_t altdist = VECTOR(dist)[j] + VECTOR(*weights)[nei];
182
85.9k
                if (VECTOR(dist)[target] > altdist) {
183
                    /* relax the edge */
184
38.0k
                    VECTOR(dist)[target] = altdist;
185
38.0k
                    if (IGRAPH_BIT_TEST(clean_vertices, target)) {
186
24.9k
                        IGRAPH_BIT_CLEAR(clean_vertices, target);
187
24.9k
                        IGRAPH_CHECK(igraph_dqueue_int_push(&Q, target));
188
24.9k
                    }
189
38.0k
                }
190
85.9k
            }
191
39.4k
        }
192
193
        /* Copy it to the result */
194
2.88k
        if (all_to) {
195
2.88k
            IGRAPH_CHECK(igraph_matrix_set_row(res, &dist, i));
196
2.88k
        } else {
197
0
            igraph_int_t j;
198
0
            for (IGRAPH_VIT_RESET(tovit), j = 0; !IGRAPH_VIT_END(tovit);
199
0
                 IGRAPH_VIT_NEXT(tovit), j++) {
200
0
                igraph_int_t v = IGRAPH_VIT_GET(tovit);
201
0
                MATRIX(*res, i, j) = VECTOR(dist)[v];
202
0
            }
203
0
        }
204
2.88k
    }
205
206
2.88k
    igraph_vector_destroy(&dist);
207
2.88k
    IGRAPH_FINALLY_CLEAN(1);
208
209
2.88k
    if (!all_to) {
210
0
        igraph_vit_destroy(&tovit);
211
0
        IGRAPH_FINALLY_CLEAN(1);
212
0
    }
213
214
2.88k
    igraph_vit_destroy(&fromvit);
215
2.88k
    igraph_dqueue_int_destroy(&Q);
216
2.88k
    igraph_bitset_destroy(&clean_vertices);
217
2.88k
    igraph_vector_int_destroy(&num_queued);
218
2.88k
    igraph_lazy_inclist_destroy(&inclist);
219
2.88k
    IGRAPH_FINALLY_CLEAN(5);
220
221
2.88k
    return IGRAPH_SUCCESS;
222
2.88k
}
223
224
225
/**
226
 * \ingroup structural
227
 * \function igraph_get_shortest_paths_bellman_ford
228
 * \brief Weighted shortest paths from a vertex, allowing negative weights.
229
 *
230
 * This function calculates weighted shortest paths from or to a single vertex
231
 * using the Bellman-Ford algorithm, whihc can handle negative weights. When
232
 * there is more than one shortest path between two vertices, only one of them
233
 * is returned. When there are no negative weights,
234
 * \ref igraph_get_shortest_paths_dijkstra() is likely to be faster.
235
 *
236
 * \param graph The input graph, can be directed.
237
 * \param vertices The result, the IDs of the vertices along the paths.
238
 *        This is a list of integer vectors where each element is an
239
 *        \ref igraph_vector_int_t object. The list will be resized as needed.
240
 *        Supply a null pointer here if you don't need these vectors.
241
 * \param edges The result, the IDs of the edges along the paths.
242
 *        This is a list of integer vectors where each element is an
243
 *        \ref igraph_vector_int_t object. The list will be resized as needed.
244
 *        Supply a null pointer here if you don't need these vectors.
245
 * \param from The id of the vertex from/to which the geodesics are
246
 *        calculated.
247
 * \param to Vertex sequence with the IDs of the vertices to/from which the
248
 *        shortest paths will be calculated. A vertex might be given multiple
249
 *        times.
250
 * \param weights The edge weights. There must not be any cycle in
251
 *    the graph that has a negative total weight (since this would allow
252
 *    us to decrease the weight of any path containing at least a single
253
 *    vertex of this cycle infinitely). If this is a null pointer, then the
254
 *    unweighted version, \ref igraph_get_shortest_paths() is called.
255
 *    Edges with positive infinite weights are ignored.
256
 * \param mode For directed graphs; whether to follow paths along edge
257
 *    directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
258
 *    ignore edge directions completely (\c IGRAPH_ALL). It is ignored
259
 *    for undirected graphs.
260
 * \param parents A pointer to an initialized igraph vector or null.
261
 *        If not null, a vector containing the parent of each vertex in
262
 *        the single source shortest path tree is returned here. The
263
 *        parent of vertex i in the tree is the vertex from which vertex i
264
 *        was reached. The parent of the start vertex (in the \c from
265
 *        argument) is -1. If the parent is -2, it means
266
 *        that the given vertex was not reached from the source during the
267
 *        search. Note that the search terminates if all the vertices in
268
 *        \c to are reached.
269
 * \param inbound_edges A pointer to an initialized igraph vector or null.
270
 *        If not null, a vector containing the inbound edge of each vertex in
271
 *        the single source shortest path tree is returned here. The
272
 *        inbound edge of vertex i in the tree is the edge via which vertex i
273
 *        was reached. The start vertex and vertices that were not reached
274
 *        during the search will have -1 in the corresponding entry of the
275
 *        vector. Note that the search terminates if all the vertices in
276
 *        \c to are reached.
277
 * \return Error code:
278
 *         \clist
279
 *         \cli IGRAPH_ENOMEM
280
 *           Not enough memory for temporary data.
281
 *         \cli IGRAPH_EINVAL
282
 *           The weight vector doesn't math the number of edges.
283
 *         \cli IGRAPH_EINVVID
284
 *           \p from is invalid vertex ID
285
 *         \cli IGRAPH_ENEGCYCLE
286
 *           Bellman-ford algorithm encounted a negative cycle.
287
 *         \endclist
288
 *
289
 * Time complexity: O(|E|*|V|), where |V| is the number of
290
 * vertices, |E| the number of edges.
291
 *
292
 * \sa \ref igraph_distances_bellman_ford() to compute only shortest path
293
 * lengths, but not the paths themselves; \ref igraph_get_shortest_paths() for
294
 * a non-algorithm-specific interface.
295
 */
296
igraph_error_t igraph_get_shortest_paths_bellman_ford(
297
        const igraph_t *graph,
298
        igraph_vector_int_list_t *vertices,
299
        igraph_vector_int_list_t *edges,
300
        igraph_int_t from,
301
        igraph_vs_t to,
302
        const igraph_vector_t *weights,
303
        igraph_neimode_t mode,
304
        igraph_vector_int_t *parents,
305
0
        igraph_vector_int_t *inbound_edges) {
306
307
0
    igraph_bool_t negative_weights;
308
0
    IGRAPH_CHECK(igraph_i_validate_distance_weights(graph, weights, &negative_weights));
309
0
    return igraph_i_get_shortest_paths_bellman_ford(graph, vertices, edges, from, to, weights, mode, parents, inbound_edges);
310
0
}
311
312
igraph_error_t igraph_i_get_shortest_paths_bellman_ford(
313
        const igraph_t *graph,
314
        igraph_vector_int_list_t *vertices,
315
        igraph_vector_int_list_t *edges,
316
        igraph_int_t from,
317
        igraph_vs_t to,
318
        const igraph_vector_t *weights,
319
        igraph_neimode_t mode,
320
        igraph_vector_int_t *parents,
321
0
        igraph_vector_int_t *inbound_edges) {
322
323
0
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
324
0
    igraph_int_t *parent_eids;
325
0
    igraph_lazy_inclist_t inclist;
326
0
    igraph_int_t i, j, k;
327
0
    igraph_dqueue_int_t Q;
328
0
    igraph_bitset_t clean_vertices;
329
0
    igraph_vector_int_t num_queued;
330
0
    igraph_vit_t tovit;
331
0
    igraph_vector_t dist;
332
0
    int iter = 0;
333
334
0
    if (!weights) {
335
0
        return igraph_i_get_shortest_paths_unweighted(graph, vertices, edges, from, to, mode, parents, inbound_edges);
336
0
    }
337
338
0
    if (from < 0 || from >= no_of_nodes) {
339
0
        IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID);
340
0
    }
341
342
0
    IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, no_of_nodes);
343
0
    IGRAPH_BITSET_INIT_FINALLY(&clean_vertices, no_of_nodes);
344
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&num_queued, no_of_nodes);
345
0
    IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode, IGRAPH_LOOPS));
346
0
    IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
347
348
0
    IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
349
0
    IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
350
351
0
    if (vertices) {
352
0
        IGRAPH_CHECK(igraph_vector_int_list_resize(vertices, IGRAPH_VIT_SIZE(tovit)));
353
0
    }
354
0
    if (edges) {
355
0
        IGRAPH_CHECK(igraph_vector_int_list_resize(edges, IGRAPH_VIT_SIZE(tovit)));
356
0
    }
357
358
0
    parent_eids = IGRAPH_CALLOC(no_of_nodes, igraph_int_t);
359
0
    IGRAPH_CHECK_OOM(parent_eids, "Insufficient memory for shortest paths with Bellman-Ford.");
360
0
    IGRAPH_FINALLY(igraph_free, parent_eids);
361
362
0
    IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
363
364
0
    igraph_vector_fill(&dist, IGRAPH_INFINITY);
365
0
    VECTOR(dist)[from] = 0;
366
367
    /* Fill the queue with vertices to be checked */
368
0
    for (j = 0; j < no_of_nodes; j++) {
369
0
        IGRAPH_CHECK(igraph_dqueue_int_push(&Q, j));
370
0
    }
371
372
0
    while (!igraph_dqueue_int_empty(&Q)) {
373
0
        IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 13);
374
375
0
        j = igraph_dqueue_int_pop(&Q);
376
0
        IGRAPH_BIT_SET(clean_vertices, j);
377
0
        VECTOR(num_queued)[j] += 1;
378
0
        if (VECTOR(num_queued)[j] > no_of_nodes) {
379
0
            IGRAPH_ERROR("Negative cycle in graph while calculating distances with Bellman-Ford algorithm.",
380
0
                         IGRAPH_ENEGCYCLE);
381
0
        }
382
383
        /* If we cannot get to j in finite time yet, there is no need to relax its edges */
384
0
        if (VECTOR(dist)[j] == IGRAPH_INFINITY) {
385
0
            continue;
386
0
        }
387
388
0
        igraph_vector_int_t *neis = igraph_lazy_inclist_get(&inclist, j);
389
0
        IGRAPH_CHECK_OOM(neis, "Failed to query incident edges.");
390
391
0
        igraph_int_t nlen = igraph_vector_int_size(neis);
392
0
        for (k = 0; k < nlen; k++) {
393
0
            igraph_int_t nei = VECTOR(*neis)[k];
394
0
            igraph_int_t target = IGRAPH_OTHER(graph, nei, j);
395
0
            igraph_real_t weight = VECTOR(*weights)[nei];
396
0
            igraph_real_t altdist = VECTOR(dist)[j] + weight;
397
398
            /* infinite weights are handled correctly here; if an edge has
399
             * infinite weight, altdist will also be infinite so the condition
400
             * will never be true as if the edge was ignored */
401
402
0
            if (VECTOR(dist)[target] > altdist) {
403
                /* relax the edge */
404
0
                VECTOR(dist)[target] = altdist;
405
0
                parent_eids[target] = nei + 1;
406
0
                if (IGRAPH_BIT_TEST(clean_vertices, target)) {
407
0
                    IGRAPH_BIT_CLEAR(clean_vertices, target);
408
0
                    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, target));
409
0
                }
410
0
            }
411
0
        }
412
0
    }
413
414
    /* Create `parents' if needed */
415
0
    if (parents) {
416
0
        IGRAPH_CHECK(igraph_vector_int_resize(parents, no_of_nodes));
417
418
0
        for (i = 0; i < no_of_nodes; i++) {
419
0
            if (i == from) {
420
                /* i is the start vertex */
421
0
                VECTOR(*parents)[i] = -1;
422
0
            } else if (parent_eids[i] <= 0) {
423
                /* i was not reached */
424
0
                VECTOR(*parents)[i] = -2;
425
0
            } else {
426
                /* i was reached via the edge with ID = parent_eids[i] - 1 */
427
0
                VECTOR(*parents)[i] = IGRAPH_OTHER(graph, parent_eids[i] - 1, i);
428
0
            }
429
0
        }
430
0
    }
431
432
    /* Create `inbound_edges' if needed */
433
0
    if (inbound_edges) {
434
0
        IGRAPH_CHECK(igraph_vector_int_resize(inbound_edges, no_of_nodes));
435
436
0
        for (i = 0; i < no_of_nodes; i++) {
437
0
            if (parent_eids[i] <= 0) {
438
                /* i was not reached */
439
0
                VECTOR(*inbound_edges)[i] = -1;
440
0
            } else {
441
                /* i was reached via the edge with ID = parent_eids[i] - 1 */
442
0
                VECTOR(*inbound_edges)[i] = parent_eids[i] - 1;
443
0
            }
444
0
        }
445
0
    }
446
447
    /* Reconstruct the shortest paths based on vertex and/or edge IDs */
448
0
    if (vertices || edges) {
449
0
        for (IGRAPH_VIT_RESET(tovit), i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit), i++) {
450
0
            igraph_int_t node = IGRAPH_VIT_GET(tovit);
451
0
            igraph_int_t size, act, edge;
452
0
            igraph_vector_int_t *vvec = 0, *evec = 0;
453
0
            if (vertices) {
454
0
                vvec = igraph_vector_int_list_get_ptr(vertices, i);
455
0
                igraph_vector_int_clear(vvec);
456
0
            }
457
0
            if (edges) {
458
0
                evec = igraph_vector_int_list_get_ptr(edges, i);
459
0
                igraph_vector_int_clear(evec);
460
0
            }
461
462
0
            IGRAPH_ALLOW_INTERRUPTION();
463
464
0
            size = 0;
465
0
            act = node;
466
0
            while (parent_eids[act]) {
467
0
                size++;
468
0
                edge = parent_eids[act] - 1;
469
0
                act = IGRAPH_OTHER(graph, edge, act);
470
0
            }
471
0
            if (vvec && (size > 0 || node == from)) {
472
0
                IGRAPH_CHECK(igraph_vector_int_resize(vvec, size + 1));
473
0
                VECTOR(*vvec)[size] = node;
474
0
            }
475
0
            if (evec) {
476
0
                IGRAPH_CHECK(igraph_vector_int_resize(evec, size));
477
0
            }
478
0
            act = node;
479
0
            while (parent_eids[act]) {
480
0
                edge = parent_eids[act] - 1;
481
0
                act = IGRAPH_OTHER(graph, edge, act);
482
0
                size--;
483
0
                if (vvec) {
484
0
                    VECTOR(*vvec)[size] = act;
485
0
                }
486
0
                if (evec) {
487
0
                    VECTOR(*evec)[size] = edge;
488
0
                }
489
0
            }
490
0
        }
491
0
    }
492
493
0
    igraph_vector_destroy(&dist);
494
0
    IGRAPH_FINALLY_CLEAN(1);
495
496
0
    igraph_vit_destroy(&tovit);
497
0
    IGRAPH_FINALLY_CLEAN(1);
498
499
0
    IGRAPH_FREE(parent_eids);
500
0
    igraph_dqueue_int_destroy(&Q);
501
0
    igraph_bitset_destroy(&clean_vertices);
502
0
    igraph_vector_int_destroy(&num_queued);
503
0
    igraph_lazy_inclist_destroy(&inclist);
504
0
    IGRAPH_FINALLY_CLEAN(5);
505
506
0
    return IGRAPH_SUCCESS;
507
0
}
508
509
/**
510
 * \function igraph_get_shortest_path_bellman_ford
511
 * \brief Weighted shortest path from one vertex to another one (Bellman-Ford).
512
 *
513
 * Finds a weighted shortest path from a single source vertex to
514
 * a single target using the Bellman-Ford algorithm.
515
 *
516
 * </para><para>
517
 * This function is a special case (and a wrapper) to
518
 * \ref igraph_get_shortest_paths_bellman_ford().
519
 *
520
 * \param graph The input graph, it can be directed or undirected.
521
 * \param vertices Pointer to an initialized vector or a null
522
 *        pointer. If not a null pointer, then the vertex IDs along
523
 *        the path are stored here, including the source and target
524
 *        vertices.
525
 * \param edges Pointer to an initialized vector or a null
526
 *        pointer. If not a null pointer, then the edge IDs along the
527
 *        path are stored here.
528
 * \param from The ID of the source vertex.
529
 * \param to The ID of the target vertex.
530
 * \param weights The edge weights. There must not be any cycle in
531
 *        the graph that has a negative total weight (since this would allow
532
 *        us to decrease the weight of any path containing at least a single
533
 *        vertex of this cycle infinitely). If this is a null pointer, then the
534
 *        unweighted version is called.
535
 * \param mode A constant specifying how edge directions are
536
 *        considered in directed graphs. \c IGRAPH_OUT follows edge
537
 *        directions, \c IGRAPH_IN follows the opposite directions,
538
 *        and \c IGRAPH_ALL ignores edge directions. This argument is
539
 *        ignored for undirected graphs.
540
 * \return Error code.
541
 *
542
 * Time complexity: O(|E|log|E|+|V|), |V| is the number of vertices,
543
 * |E| is the number of edges in the graph.
544
 *
545
 * \sa \ref igraph_get_shortest_paths_bellman_ford() for the version with
546
 * more target vertices.
547
 */
548
549
igraph_error_t igraph_get_shortest_path_bellman_ford(const igraph_t *graph,
550
                                          igraph_vector_int_t *vertices,
551
                                          igraph_vector_int_t *edges,
552
                                          igraph_int_t from,
553
                                          igraph_int_t to,
554
                                          const igraph_vector_t *weights,
555
0
                                          igraph_neimode_t mode) {
556
557
0
    igraph_vector_int_list_t vertices2, *vp = &vertices2;
558
0
    igraph_vector_int_list_t edges2, *ep = &edges2;
559
560
0
    if (vertices) {
561
0
        IGRAPH_CHECK(igraph_vector_int_list_init(&vertices2, 1));
562
0
        IGRAPH_FINALLY(igraph_vector_int_list_destroy, &vertices2);
563
0
    } else {
564
0
        vp = NULL;
565
0
    }
566
0
    if (edges) {
567
0
        IGRAPH_CHECK(igraph_vector_int_list_init(&edges2, 1));
568
0
        IGRAPH_FINALLY(igraph_vector_int_list_destroy, &edges2);
569
0
    } else {
570
0
        ep = NULL;
571
0
    }
572
573
0
    IGRAPH_CHECK(igraph_get_shortest_paths_bellman_ford(graph, vp, ep,
574
0
                                                        from, igraph_vss_1(to),
575
0
                                                        weights, mode, NULL, NULL));
576
577
    /* We use the constant time vector_swap() instead of the linear-time vector_update() to move the
578
       result to the output parameter. */
579
0
    if (edges) {
580
0
        igraph_vector_int_swap(edges, igraph_vector_int_list_get_ptr(&edges2, 0));
581
0
        igraph_vector_int_list_destroy(&edges2);
582
0
        IGRAPH_FINALLY_CLEAN(1);
583
0
    }
584
0
    if (vertices) {
585
0
        igraph_vector_int_swap(vertices, igraph_vector_int_list_get_ptr(&vertices2, 0));
586
0
        igraph_vector_int_list_destroy(&vertices2);
587
0
        IGRAPH_FINALLY_CLEAN(1);
588
0
    }
589
590
0
    return IGRAPH_SUCCESS;
591
0
}