/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 | } |