Coverage Report

Created: 2025-10-10 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/paths/simple_paths.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2014-2024  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
20
#include "igraph_paths.h"
21
22
#include "igraph_adjlist.h"
23
#include "igraph_bitset.h"
24
#include "igraph_interface.h"
25
#include "igraph_iterators.h"
26
#include "igraph_vector_list.h"
27
28
#include "core/interruption.h"
29
30
/**
31
 * \function igraph_get_all_simple_paths
32
 * \brief List all simple paths from one source.
33
 *
34
 * A path is simple if its vertices are unique, i.e. no vertex is visited more
35
 * than once. This function returns paths in terms of their vertices and
36
 * ignores multi-edges.
37
 *
38
 * </para><para>
39
 * Note that potentially there are exponentially many paths between two
40
 * vertices of a graph, and you may run out of memory when using this function
41
 * when the graph has many cycles. Consider using the \p minlen and \p maxlen
42
 * parameters to restrict the paths that are returned.
43
 *
44
 * \param graph The input graph.
45
 * \param res Initialized integer vector list. The paths are returned here in
46
 *   terms of their vertices. The paths are included in arbitrary order, as
47
 *   they are found.
48
 * \param from The start vertex.
49
 * \param to The target vertices.
50
 * \param mode The type of paths to be used for the calculation in directed
51
 *   graphs. Possible values:
52
 *        \clist
53
 *        \cli IGRAPH_OUT
54
 *          outgoing paths are calculated.
55
 *        \cli IGRAPH_IN
56
 *          incoming paths are calculated.
57
 *        \cli IGRAPH_ALL
58
 *          the directed graph is considered as an undirected one for
59
 *          the computation.
60
 *        \endclist
61
 * \param minlen Minimum length of paths that is considered. If negative
62
 *   or \ref IGRAPH_UNLIMITED, no lower bound is used on the path lengths.
63
 * \param maxlen Maximum length of paths that is considered. If negative
64
 *   or \ref IGRAPH_UNLIMITED, no upper bound is used on the path lengths.
65
 * \param max_results At most this many paths will be recorded. If
66
 *   negative, or \ref IGRAPH_UNLIMITED, no limit is applied.
67
 * \return Error code.
68
 *
69
 * \sa \ref igraph_get_k_shortest_paths()
70
 *
71
 * Time complexity: O(n!) in the worst case, n is the number of
72
 * vertices.
73
 */
74
75
igraph_error_t igraph_get_all_simple_paths(
76
        const igraph_t *graph,
77
        igraph_vector_int_list_t *res,
78
        igraph_int_t from, const igraph_vs_t to,
79
        igraph_neimode_t mode,
80
        igraph_int_t minlen, igraph_int_t maxlen,
81
1.73k
        igraph_int_t max_results) {
82
83
1.73k
    const igraph_int_t vcount = igraph_vcount(graph);
84
1.73k
    const igraph_bool_t toall = igraph_vs_is_all(&to);
85
1.73k
    igraph_vit_t vit;
86
1.73k
    igraph_lazy_adjlist_t adjlist;
87
1.73k
    igraph_vector_int_t stack, dist; /* used as a stack, but represented as a vector,
88
                                        in order to be appendable the result vector list */
89
1.73k
    igraph_bitset_t markto, added;
90
1.73k
    igraph_vector_int_t nptr;
91
1.73k
    int iter = 0;
92
93
1.73k
    if (from < 0 || from >= vcount) {
94
0
        IGRAPH_ERROR("Index of source vertex is out of range.", IGRAPH_EINVVID);
95
0
    }
96
97
1.73k
    igraph_vector_int_list_clear(res);
98
99
1.73k
    if (max_results == 0) {
100
0
        return IGRAPH_SUCCESS;
101
0
    }
102
103
1.73k
    if (!toall) {
104
1.73k
        IGRAPH_BITSET_INIT_FINALLY(&markto, vcount);
105
1.73k
        IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
106
1.73k
        IGRAPH_FINALLY(igraph_vit_destroy, &vit);
107
3.46k
        for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
108
1.73k
            IGRAPH_BIT_SET(markto, IGRAPH_VIT_GET(vit));
109
1.73k
        }
110
1.73k
        igraph_vit_destroy(&vit);
111
1.73k
        IGRAPH_FINALLY_CLEAN(1);
112
1.73k
    }
113
114
1.73k
    IGRAPH_BITSET_INIT_FINALLY(&added, vcount);
115
1.73k
    IGRAPH_VECTOR_INT_INIT_FINALLY(&stack, 100);
116
1.73k
    IGRAPH_VECTOR_INT_INIT_FINALLY(&dist, 100);
117
1.73k
    IGRAPH_CHECK(igraph_lazy_adjlist_init(
118
1.73k
        graph, &adjlist, mode, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE
119
1.73k
    ));
120
1.73k
    IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
121
1.73k
    IGRAPH_VECTOR_INT_INIT_FINALLY(&nptr, vcount);
122
123
1.73k
    igraph_vector_int_clear(&stack);
124
1.73k
    igraph_vector_int_clear(&dist);
125
1.73k
    igraph_vector_int_push_back(&stack, from);
126
1.73k
    igraph_vector_int_push_back(&dist, 0);
127
1.73k
    IGRAPH_BIT_SET(added, from);
128
1.98M
    while (!igraph_vector_int_empty(&stack)) {
129
1.98M
        const igraph_int_t act = igraph_vector_int_tail(&stack);
130
1.98M
        const igraph_int_t curdist = igraph_vector_int_tail(&dist);
131
132
1.98M
        const igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, act);
133
1.98M
        IGRAPH_CHECK_OOM(neis, "Failed to query neighbors.");
134
135
1.98M
        const igraph_int_t n = igraph_vector_int_size(neis);
136
1.98M
        igraph_int_t *ptr = igraph_vector_int_get_ptr(&nptr, act);
137
1.98M
        igraph_bool_t any;
138
1.98M
        igraph_bool_t within_dist;
139
1.98M
        igraph_int_t nei;
140
141
1.98M
        within_dist = (curdist < maxlen || maxlen < 0);
142
1.98M
        if (within_dist) {
143
            /* Search for a neighbor that was not yet visited */
144
1.19M
            any = false;
145
2.66M
            while (!any && (*ptr) < n) {
146
1.47M
                nei = VECTOR(*neis)[(*ptr)];
147
1.47M
                any = !IGRAPH_BIT_TEST(added, nei);
148
1.47M
                (*ptr) ++;
149
1.47M
            }
150
1.19M
        }
151
1.98M
        if (within_dist && any) {
152
            /* There is such a neighbor, add it */
153
992k
            IGRAPH_CHECK(igraph_vector_int_push_back(&stack, nei));
154
992k
            IGRAPH_CHECK(igraph_vector_int_push_back(&dist, curdist + 1));
155
992k
            IGRAPH_BIT_SET(added, nei);
156
            /* Add to results */
157
992k
            if (toall || IGRAPH_BIT_TEST(markto, nei)) {
158
50.2k
                if (curdist + 1 >= minlen) {
159
50.2k
                    IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(res, &stack));
160
50.2k
                    if (max_results >= 0 && igraph_vector_int_list_size(res) == max_results) {
161
0
                        break;
162
0
                    }
163
50.2k
                }
164
50.2k
            }
165
994k
        } else {
166
            /* There is no such neighbor, finished with the subtree */
167
994k
            igraph_int_t up = igraph_vector_int_pop_back(&stack);
168
994k
            igraph_vector_int_pop_back(&dist);
169
994k
            IGRAPH_BIT_CLEAR(added, up);
170
994k
            VECTOR(nptr)[up] = 0;
171
994k
        }
172
173
1.98M
        IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 13);
174
1.98M
    }
175
176
1.73k
    igraph_vector_int_destroy(&nptr);
177
1.73k
    igraph_lazy_adjlist_destroy(&adjlist);
178
1.73k
    igraph_vector_int_destroy(&dist);
179
1.73k
    igraph_vector_int_destroy(&stack);
180
1.73k
    igraph_bitset_destroy(&added);
181
1.73k
    IGRAPH_FINALLY_CLEAN(5);
182
183
1.73k
    if (!toall) {
184
1.73k
        igraph_bitset_destroy(&markto);
185
1.73k
        IGRAPH_FINALLY_CLEAN(1);
186
1.73k
    }
187
188
1.73k
    return IGRAPH_SUCCESS;
189
1.73k
}