/src/igraph/src/flow/st-cuts.c
Line | Count | Source |
1 | | /* |
2 | | igraph library. |
3 | | Copyright (C) 2010-2021 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, write to the Free Software |
17 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | | 02110-1301 USA |
19 | | |
20 | | */ |
21 | | |
22 | | #include "igraph_flow.h" |
23 | | |
24 | | #include "igraph_adjlist.h" |
25 | | #include "igraph_bitset.h" |
26 | | #include "igraph_constants.h" |
27 | | #include "igraph_constructors.h" |
28 | | #include "igraph_components.h" |
29 | | #include "igraph_cycles.h" |
30 | | #include "igraph_error.h" |
31 | | #include "igraph_interface.h" |
32 | | #include "igraph_operators.h" |
33 | | #include "igraph_stack.h" |
34 | | #include "igraph_visitor.h" |
35 | | |
36 | | #include "core/estack.h" |
37 | | #include "core/marked_queue.h" |
38 | | #include "flow/flow_internal.h" |
39 | | #include "graph/attributes.h" |
40 | | #include "math/safe_intop.h" |
41 | | |
42 | | typedef igraph_error_t igraph_provan_shier_pivot_t(const igraph_t *graph, |
43 | | const igraph_marked_queue_int_t *S, |
44 | | const igraph_estack_t *T, |
45 | | igraph_int_t source, |
46 | | igraph_int_t target, |
47 | | igraph_int_t *v, |
48 | | igraph_vector_int_t *Isv, |
49 | | void *arg); |
50 | | |
51 | | /** |
52 | | * \function igraph_even_tarjan_reduction |
53 | | * \brief Even-Tarjan reduction of a graph. |
54 | | * |
55 | | * A digraph is created with twice as many vertices and edges. For each |
56 | | * original vertex \c i, two vertices <code>i' = i</code> and |
57 | | * <code>i'' = i' + n</code> are created, |
58 | | * with a directed edge from <code>i'</code> to <code>i''</code>. |
59 | | * For each original directed edge from \c i to \c j, two new edges are created, |
60 | | * from <code>i'</code> to <code>j''</code> and from <code>i''</code> |
61 | | * to <code>j'</code>. |
62 | | * |
63 | | * </para><para>This reduction is used in the paper (observation 2): |
64 | | * Arkady Kanevsky: Finding all minimum-size separating vertex sets in |
65 | | * a graph, Networks 23, 533--541, 1993. |
66 | | * |
67 | | * </para><para>The original paper where this reduction was conceived is |
68 | | * Shimon Even and R. Endre Tarjan: Network Flow and Testing Graph |
69 | | * Connectivity, SIAM J. Comput., 4(4), 507–518. |
70 | | * https://doi.org/10.1137/0204043 |
71 | | * |
72 | | * \param graph A graph. Although directness is not checked, this function |
73 | | * is commonly used only on directed graphs. |
74 | | * \param graphbar Pointer to a new directed graph that will contain the |
75 | | * reduction, with twice as many vertices and edges. |
76 | | * \param capacity Pointer to an initialized vector or a null pointer. If |
77 | | * not a null pointer, then it will be filled the capacity from |
78 | | * the reduction: the first |E| elements are 1, the remaining |E| |
79 | | * are equal to |V| (which is used to indicate infinity). |
80 | | * \return Error code. |
81 | | * |
82 | | * Time complexity: O(|E|+|V|). |
83 | | * |
84 | | * \example examples/simple/even_tarjan.c |
85 | | */ |
86 | | |
87 | | igraph_error_t igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar, |
88 | 0 | igraph_vector_t *capacity) { |
89 | |
|
90 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
91 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
92 | |
|
93 | 0 | igraph_int_t new_no_of_nodes; |
94 | 0 | igraph_int_t new_no_of_edges = no_of_edges * 2; |
95 | |
|
96 | 0 | igraph_vector_int_t edges; |
97 | 0 | igraph_int_t edgeptr = 0, capptr = 0; |
98 | 0 | igraph_int_t i; |
99 | |
|
100 | 0 | IGRAPH_SAFE_MULT(no_of_nodes, 2, &new_no_of_nodes); |
101 | 0 | IGRAPH_SAFE_ADD(new_no_of_edges, no_of_nodes, &new_no_of_edges); |
102 | | |
103 | | /* To ensure the size of the edges vector will not overflow. */ |
104 | 0 | if (new_no_of_edges > IGRAPH_ECOUNT_MAX) { |
105 | 0 | IGRAPH_ERROR("Overflow in number of edges.", IGRAPH_EOVERFLOW); |
106 | 0 | } |
107 | | |
108 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, new_no_of_edges * 2); |
109 | | |
110 | 0 | if (capacity) { |
111 | 0 | IGRAPH_CHECK(igraph_vector_resize(capacity, new_no_of_edges)); |
112 | 0 | } |
113 | | |
114 | | /* Every vertex 'i' is replaced by two vertices, i' and i'' */ |
115 | | /* id[i'] := id[i] ; id[i''] := id[i] + no_of_nodes */ |
116 | | |
117 | | /* One edge for each original vertex, for i, we add (i',i'') */ |
118 | 0 | for (i = 0; i < no_of_nodes; i++) { |
119 | 0 | VECTOR(edges)[edgeptr++] = i; |
120 | 0 | VECTOR(edges)[edgeptr++] = i + no_of_nodes; |
121 | 0 | if (capacity) { |
122 | 0 | VECTOR(*capacity)[capptr++] = 1.0; |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | /* Two news edges for each original edge |
127 | | (from,to) becomes (from'',to'), (to'',from') */ |
128 | 0 | for (i = 0; i < no_of_edges; i++) { |
129 | 0 | igraph_int_t from = IGRAPH_FROM(graph, i); |
130 | 0 | igraph_int_t to = IGRAPH_TO(graph, i); |
131 | 0 | VECTOR(edges)[edgeptr++] = from + no_of_nodes; |
132 | 0 | VECTOR(edges)[edgeptr++] = to; |
133 | 0 | VECTOR(edges)[edgeptr++] = to + no_of_nodes; |
134 | 0 | VECTOR(edges)[edgeptr++] = from; |
135 | 0 | if (capacity) { |
136 | 0 | VECTOR(*capacity)[capptr++] = no_of_nodes; /* TODO: should be Inf */ |
137 | 0 | VECTOR(*capacity)[capptr++] = no_of_nodes; /* TODO: should be Inf */ |
138 | 0 | } |
139 | 0 | } |
140 | |
|
141 | 0 | IGRAPH_CHECK(igraph_create(graphbar, &edges, new_no_of_nodes, |
142 | 0 | IGRAPH_DIRECTED)); |
143 | | |
144 | 0 | igraph_vector_int_destroy(&edges); |
145 | 0 | IGRAPH_FINALLY_CLEAN(1); |
146 | |
|
147 | 0 | return IGRAPH_SUCCESS; |
148 | 0 | } |
149 | | |
150 | | static igraph_error_t igraph_i_residual_graph(const igraph_t *graph, |
151 | | const igraph_vector_t *capacity, |
152 | | igraph_t *residual, |
153 | | igraph_vector_t *residual_capacity, |
154 | | const igraph_vector_t *flow, |
155 | 0 | igraph_vector_int_t *tmp) { |
156 | |
|
157 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
158 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
159 | 0 | igraph_int_t i, no_new_edges = 0; |
160 | 0 | igraph_int_t edgeptr = 0, capptr = 0; |
161 | |
|
162 | 0 | for (i = 0; i < no_of_edges; i++) { |
163 | 0 | if (VECTOR(*flow)[i] < VECTOR(*capacity)[i]) { |
164 | 0 | no_new_edges++; |
165 | 0 | } |
166 | 0 | } |
167 | |
|
168 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(tmp, no_new_edges * 2)); |
169 | 0 | if (residual_capacity) { |
170 | 0 | IGRAPH_CHECK(igraph_vector_resize(residual_capacity, no_new_edges)); |
171 | 0 | } |
172 | | |
173 | 0 | for (i = 0; i < no_of_edges; i++) { |
174 | 0 | igraph_real_t c = VECTOR(*capacity)[i] - VECTOR(*flow)[i]; |
175 | 0 | if (c > 0) { |
176 | 0 | igraph_int_t from = IGRAPH_FROM(graph, i); |
177 | 0 | igraph_int_t to = IGRAPH_TO(graph, i); |
178 | 0 | VECTOR(*tmp)[edgeptr++] = from; |
179 | 0 | VECTOR(*tmp)[edgeptr++] = to; |
180 | 0 | if (residual_capacity) { |
181 | 0 | VECTOR(*residual_capacity)[capptr++] = c; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | } |
185 | |
|
186 | 0 | IGRAPH_CHECK(igraph_create(residual, tmp, no_of_nodes, |
187 | 0 | IGRAPH_DIRECTED)); |
188 | | |
189 | 0 | return IGRAPH_SUCCESS; |
190 | 0 | } |
191 | | |
192 | | igraph_error_t igraph_residual_graph(const igraph_t *graph, |
193 | | const igraph_vector_t *capacity, |
194 | | igraph_t *residual, |
195 | | igraph_vector_t *residual_capacity, |
196 | 0 | const igraph_vector_t *flow) { |
197 | |
|
198 | 0 | igraph_vector_int_t tmp; |
199 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
200 | |
|
201 | 0 | if (igraph_vector_size(capacity) != no_of_edges) { |
202 | 0 | IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL); |
203 | 0 | } |
204 | 0 | if (igraph_vector_size(flow) != no_of_edges) { |
205 | 0 | IGRAPH_ERROR("Invalid `flow' vector size", IGRAPH_EINVAL); |
206 | 0 | } |
207 | | |
208 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0); |
209 | | |
210 | 0 | IGRAPH_CHECK(igraph_i_residual_graph(graph, capacity, residual, |
211 | 0 | residual_capacity, flow, &tmp)); |
212 | | |
213 | 0 | igraph_vector_int_destroy(&tmp); |
214 | 0 | IGRAPH_FINALLY_CLEAN(1); |
215 | |
|
216 | 0 | return IGRAPH_SUCCESS; |
217 | 0 | } |
218 | | |
219 | | static igraph_error_t igraph_i_reverse_residual_graph(const igraph_t *graph, |
220 | | const igraph_vector_t *capacity, |
221 | | igraph_t *residual, |
222 | | const igraph_vector_t *flow, |
223 | 0 | igraph_vector_int_t *tmp) { |
224 | |
|
225 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
226 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
227 | 0 | igraph_int_t i, no_new_edges = 0; |
228 | 0 | igraph_int_t edgeptr = 0; |
229 | |
|
230 | 0 | for (i = 0; i < no_of_edges; i++) { |
231 | 0 | igraph_real_t cap = capacity ? VECTOR(*capacity)[i] : 1.0; |
232 | 0 | if (VECTOR(*flow)[i] > 0) { |
233 | 0 | no_new_edges++; |
234 | 0 | } |
235 | 0 | if (VECTOR(*flow)[i] < cap) { |
236 | 0 | no_new_edges++; |
237 | 0 | } |
238 | 0 | } |
239 | |
|
240 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(tmp, no_new_edges * 2)); |
241 | | |
242 | 0 | for (i = 0; i < no_of_edges; i++) { |
243 | 0 | igraph_int_t from = IGRAPH_FROM(graph, i); |
244 | 0 | igraph_int_t to = IGRAPH_TO(graph, i); |
245 | 0 | igraph_real_t cap = capacity ? VECTOR(*capacity)[i] : 1.0; |
246 | 0 | if (VECTOR(*flow)[i] > 0) { |
247 | 0 | VECTOR(*tmp)[edgeptr++] = from; |
248 | 0 | VECTOR(*tmp)[edgeptr++] = to; |
249 | 0 | } |
250 | 0 | if (VECTOR(*flow)[i] < cap) { |
251 | 0 | VECTOR(*tmp)[edgeptr++] = to; |
252 | 0 | VECTOR(*tmp)[edgeptr++] = from; |
253 | 0 | } |
254 | 0 | } |
255 | |
|
256 | 0 | IGRAPH_CHECK(igraph_create(residual, tmp, no_of_nodes, |
257 | 0 | IGRAPH_DIRECTED)); |
258 | | |
259 | 0 | return IGRAPH_SUCCESS; |
260 | 0 | } |
261 | | |
262 | | igraph_error_t igraph_reverse_residual_graph(const igraph_t *graph, |
263 | | const igraph_vector_t *capacity, |
264 | | igraph_t *residual, |
265 | 0 | const igraph_vector_t *flow) { |
266 | 0 | igraph_vector_int_t tmp; |
267 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
268 | |
|
269 | 0 | if (capacity && igraph_vector_size(capacity) != no_of_edges) { |
270 | 0 | IGRAPH_ERROR("Invalid `capacity' vector size", IGRAPH_EINVAL); |
271 | 0 | } |
272 | 0 | if (igraph_vector_size(flow) != no_of_edges) { |
273 | 0 | IGRAPH_ERROR("Invalid `flow' vector size", IGRAPH_EINVAL); |
274 | 0 | } |
275 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0); |
276 | | |
277 | 0 | IGRAPH_CHECK(igraph_i_reverse_residual_graph(graph, capacity, residual, |
278 | 0 | flow, &tmp)); |
279 | | |
280 | 0 | igraph_vector_int_destroy(&tmp); |
281 | 0 | IGRAPH_FINALLY_CLEAN(1); |
282 | |
|
283 | 0 | return IGRAPH_SUCCESS; |
284 | 0 | } |
285 | | |
286 | | typedef struct igraph_i_dbucket_t { |
287 | | igraph_vector_int_t head; |
288 | | igraph_vector_int_t next; |
289 | | } igraph_i_dbucket_t; |
290 | | |
291 | 1.77k | static igraph_error_t igraph_i_dbucket_init(igraph_i_dbucket_t *buck, igraph_int_t size) { |
292 | 1.77k | IGRAPH_VECTOR_INT_INIT_FINALLY(&buck->head, size); |
293 | 1.77k | IGRAPH_CHECK(igraph_vector_int_init(&buck->next, size)); |
294 | 1.77k | IGRAPH_FINALLY_CLEAN(1); |
295 | 1.77k | return IGRAPH_SUCCESS; |
296 | 1.77k | } |
297 | | |
298 | 1.77k | static void igraph_i_dbucket_destroy(igraph_i_dbucket_t *buck) { |
299 | 1.77k | igraph_vector_int_destroy(&buck->head); |
300 | 1.77k | igraph_vector_int_destroy(&buck->next); |
301 | 1.77k | } |
302 | | |
303 | | static igraph_error_t igraph_i_dbucket_insert(igraph_i_dbucket_t *buck, igraph_int_t bid, |
304 | 22.1k | igraph_int_t elem) { |
305 | | /* Note: we can do this, since elem is not in any buckets */ |
306 | 22.1k | VECTOR(buck->next)[elem] = VECTOR(buck->head)[bid]; |
307 | 22.1k | VECTOR(buck->head)[bid] = elem + 1; |
308 | 22.1k | return IGRAPH_SUCCESS; |
309 | 22.1k | } |
310 | | |
311 | | static igraph_bool_t igraph_i_dbucket_empty(const igraph_i_dbucket_t *buck, |
312 | 44.2k | igraph_int_t bid) { |
313 | 44.2k | return VECTOR(buck->head)[bid] == 0; |
314 | 44.2k | } |
315 | | |
316 | 22.1k | static igraph_int_t igraph_i_dbucket_delete(igraph_i_dbucket_t *buck, igraph_int_t bid) { |
317 | 22.1k | igraph_int_t elem = VECTOR(buck->head)[bid] - 1; |
318 | 22.1k | VECTOR(buck->head)[bid] = VECTOR(buck->next)[elem]; |
319 | 22.1k | return elem; |
320 | 22.1k | } |
321 | | |
322 | | static igraph_error_t igraph_i_dominator_LINK(igraph_int_t v, igraph_int_t w, |
323 | 22.1k | igraph_vector_int_t *ancestor) { |
324 | 22.1k | VECTOR(*ancestor)[w] = v + 1; |
325 | 22.1k | return IGRAPH_SUCCESS; |
326 | 22.1k | } |
327 | | |
328 | | /* TODO: don't always reallocate path */ |
329 | | |
330 | | static igraph_error_t igraph_i_dominator_COMPRESS(igraph_int_t v, |
331 | | igraph_vector_int_t *ancestor, |
332 | | igraph_vector_int_t *label, |
333 | 26.0k | igraph_vector_int_t *semi) { |
334 | 26.0k | igraph_stack_int_t path; |
335 | 26.0k | igraph_int_t w = v; |
336 | 26.0k | igraph_int_t top, pretop; |
337 | | |
338 | 26.0k | IGRAPH_CHECK(igraph_stack_int_init(&path, 10)); |
339 | 26.0k | IGRAPH_FINALLY(igraph_stack_int_destroy, &path); |
340 | | |
341 | 64.5k | while (VECTOR(*ancestor)[w] != 0) { |
342 | 38.4k | IGRAPH_CHECK(igraph_stack_int_push(&path, w)); |
343 | 38.4k | w = VECTOR(*ancestor)[w] - 1; |
344 | 38.4k | } |
345 | | |
346 | 26.0k | top = igraph_stack_int_pop(&path); |
347 | 38.4k | while (!igraph_stack_int_empty(&path)) { |
348 | 12.4k | pretop = igraph_stack_int_pop(&path); |
349 | | |
350 | 12.4k | if (VECTOR(*semi)[VECTOR(*label)[top]] < |
351 | 12.4k | VECTOR(*semi)[VECTOR(*label)[pretop]]) { |
352 | 9.53k | VECTOR(*label)[pretop] = VECTOR(*label)[top]; |
353 | 9.53k | } |
354 | 12.4k | VECTOR(*ancestor)[pretop] = VECTOR(*ancestor)[top]; |
355 | | |
356 | 12.4k | top = pretop; |
357 | 12.4k | } |
358 | | |
359 | 26.0k | igraph_stack_int_destroy(&path); |
360 | 26.0k | IGRAPH_FINALLY_CLEAN(1); |
361 | | |
362 | 26.0k | return IGRAPH_SUCCESS; |
363 | 26.0k | } |
364 | | |
365 | | static igraph_int_t igraph_i_dominator_EVAL(igraph_int_t v, |
366 | | igraph_vector_int_t *ancestor, |
367 | | igraph_vector_int_t *label, |
368 | 55.1k | igraph_vector_int_t *semi) { |
369 | 55.1k | if (VECTOR(*ancestor)[v] == 0) { |
370 | 29.1k | return v; |
371 | 29.1k | } else { |
372 | 26.0k | igraph_i_dominator_COMPRESS(v, ancestor, label, semi); |
373 | 26.0k | return VECTOR(*label)[v]; |
374 | 26.0k | } |
375 | 55.1k | } |
376 | | |
377 | | /* TODO: implement the faster version. */ |
378 | | |
379 | | /** |
380 | | * \function igraph_dominator_tree |
381 | | * \brief Calculates the dominator tree of a flowgraph. |
382 | | * |
383 | | * A flowgraph is a directed graph with a distinguished start (or |
384 | | * root) vertex r, such that for any vertex v, there is a path from r |
385 | | * to v. A vertex v dominates another vertex w (not equal to v), if |
386 | | * every path from r to w contains v. Vertex v is the immediate |
387 | | * dominator or w, v=idom(w), if v dominates w and every other |
388 | | * dominator of w dominates v. The edges {(idom(w), w)| w is not r} |
389 | | * form a directed tree, rooted at r, called the dominator tree of the |
390 | | * graph. Vertex v dominates vertex w if and only if v is an ancestor |
391 | | * of w in the dominator tree. |
392 | | * |
393 | | * </para><para>This function implements the Lengauer-Tarjan algorithm |
394 | | * to construct the dominator tree of a directed graph. For details |
395 | | * please see Thomas Lengauer, Robert Endre Tarjan: A fast algorithm |
396 | | * for finding dominators in a flowgraph, ACM Transactions on |
397 | | * Programming Languages and Systems (TOPLAS) I/1, 121--141, 1979. |
398 | | * https://doi.org/10.1145/357062.357071 |
399 | | * |
400 | | * \param graph A directed graph. If it is not a flowgraph, and it |
401 | | * contains some vertices not reachable from the root vertex, |
402 | | * then these vertices will be collected in the \p leftout |
403 | | * vector. |
404 | | * \param root The ID of the root (or source) vertex, this will be the |
405 | | * root of the tree. |
406 | | * \param dom Pointer to an initialized vector or a null pointer. If |
407 | | * not a null pointer, then the immediate dominator of each |
408 | | * vertex will be stored here. For vertices that are not |
409 | | * reachable from the root, <code>-2</code> is stored here. For |
410 | | * the root vertex itself, <code>-1</code> is added. |
411 | | * \param domtree Pointer to an \em uninitialized <type>igraph_t</type>, |
412 | | * or \c NULL. If not a null pointer, then the dominator tree |
413 | | * is returned here. The graph contains the vertices that are unreachable |
414 | | * from the root (if any), these will be isolates. |
415 | | * Graph and vertex attributes are preserved, but edge attributes |
416 | | * are discarded. |
417 | | * \param leftout Pointer to an initialized vector object, or \c NULL. If |
418 | | * not \c NULL, then the IDs of the vertices that are unreachable |
419 | | * from the root vertex (and thus not part of the dominator |
420 | | * tree) are stored here. |
421 | | * \param mode Constant, must be \c IGRAPH_IN or \c IGRAPH_OUT. If it |
422 | | * is \c IGRAPH_IN, then all directions are considered as |
423 | | * opposite to the original one in the input graph. |
424 | | * \return Error code. |
425 | | * |
426 | | * Time complexity: very close to O(|E|+|V|), linear in the number of |
427 | | * edges and vertices. More precisely, it is O(|V|+|E|alpha(|E|,|V|)), |
428 | | * where alpha(|E|,|V|) is a functional inverse of Ackermann's |
429 | | * function. |
430 | | * |
431 | | * \example examples/simple/dominator_tree.c |
432 | | */ |
433 | | |
434 | | igraph_error_t igraph_dominator_tree(const igraph_t *graph, |
435 | | igraph_int_t root, |
436 | | igraph_vector_int_t *dom, |
437 | | igraph_t *domtree, |
438 | | igraph_vector_int_t *leftout, |
439 | 1.77k | igraph_neimode_t mode) { |
440 | | |
441 | 1.77k | igraph_int_t no_of_nodes = igraph_vcount(graph); |
442 | | |
443 | 1.77k | igraph_adjlist_t succ, pred; |
444 | 1.77k | igraph_vector_int_t parent; |
445 | 1.77k | igraph_vector_int_t semi; /* +1 always */ |
446 | 1.77k | igraph_vector_int_t vertex; /* +1 always */ |
447 | 1.77k | igraph_i_dbucket_t bucket; |
448 | 1.77k | igraph_vector_int_t ancestor; |
449 | 1.77k | igraph_vector_int_t label; |
450 | | |
451 | 1.77k | igraph_neimode_t invmode = IGRAPH_REVERSE_MODE(mode); |
452 | | |
453 | 1.77k | igraph_vector_int_t vdom, *mydom = dom; |
454 | | |
455 | 1.77k | igraph_int_t component_size = 0; |
456 | | |
457 | 1.77k | if (root < 0 || root >= no_of_nodes) { |
458 | 0 | IGRAPH_ERROR("Invalid root vertex ID for dominator tree.", |
459 | 0 | IGRAPH_EINVVID); |
460 | 0 | } |
461 | | |
462 | 1.77k | if (!igraph_is_directed(graph)) { |
463 | 0 | IGRAPH_ERROR("Dominator tree of an undirected graph requested.", |
464 | 0 | IGRAPH_EINVAL); |
465 | 0 | } |
466 | | |
467 | 1.77k | if (mode == IGRAPH_ALL) { |
468 | 0 | IGRAPH_ERROR("Invalid neighbor mode for dominator tree.", |
469 | 0 | IGRAPH_EINVAL); |
470 | 0 | } |
471 | | |
472 | 1.77k | if (dom) { |
473 | 1.77k | IGRAPH_CHECK(igraph_vector_int_resize(dom, no_of_nodes)); |
474 | 1.77k | } else { |
475 | 0 | mydom = &vdom; |
476 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(mydom, no_of_nodes); |
477 | 0 | } |
478 | 1.77k | igraph_vector_int_fill(mydom, -2); |
479 | | |
480 | 1.77k | IGRAPH_VECTOR_INT_INIT_FINALLY(&parent, no_of_nodes); |
481 | 1.77k | IGRAPH_VECTOR_INT_INIT_FINALLY(&semi, no_of_nodes); |
482 | 1.77k | IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex, no_of_nodes); |
483 | 1.77k | IGRAPH_VECTOR_INT_INIT_FINALLY(&ancestor, no_of_nodes); |
484 | 1.77k | IGRAPH_CHECK(igraph_vector_int_init_range(&label, 0, no_of_nodes)); |
485 | 1.77k | IGRAPH_FINALLY(igraph_vector_int_destroy, &label); |
486 | 1.77k | IGRAPH_CHECK(igraph_adjlist_init(graph, &succ, mode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); |
487 | 1.77k | IGRAPH_FINALLY(igraph_adjlist_destroy, &succ); |
488 | 1.77k | IGRAPH_CHECK(igraph_adjlist_init(graph, &pred, invmode, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); |
489 | 1.77k | IGRAPH_FINALLY(igraph_adjlist_destroy, &pred); |
490 | 1.77k | IGRAPH_CHECK(igraph_i_dbucket_init(&bucket, no_of_nodes)); |
491 | 1.77k | IGRAPH_FINALLY(igraph_i_dbucket_destroy, &bucket); |
492 | | |
493 | | /* DFS first, to set semi, vertex and parent, step 1 */ |
494 | | |
495 | 1.77k | IGRAPH_CHECK(igraph_dfs(graph, root, mode, /*unreachable=*/ false, |
496 | 1.77k | /*order=*/ &vertex, |
497 | 1.77k | /*order_out=*/ NULL, /*parents=*/ &parent, |
498 | 1.77k | /*dist=*/ NULL, /*in_callback=*/ NULL, |
499 | 1.77k | /*out_callback=*/ NULL, /*extra=*/ NULL)); |
500 | | |
501 | 308k | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
502 | 306k | if (VECTOR(vertex)[i] >= 0) { |
503 | 23.8k | igraph_int_t t = VECTOR(vertex)[i]; |
504 | 23.8k | VECTOR(semi)[t] = component_size + 1; |
505 | 23.8k | VECTOR(vertex)[component_size] = t + 1; |
506 | 23.8k | component_size++; |
507 | 23.8k | } |
508 | 306k | } |
509 | 1.77k | if (leftout) { |
510 | 1.77k | igraph_int_t n = no_of_nodes - component_size; |
511 | 1.77k | igraph_int_t p = 0, j; |
512 | 1.77k | IGRAPH_CHECK(igraph_vector_int_resize(leftout, n)); |
513 | 307k | for (j = 0; j < no_of_nodes && p < n; j++) { |
514 | 305k | if (VECTOR(parent)[j] < -1) { |
515 | 282k | VECTOR(*leftout)[p++] = j; |
516 | 282k | } |
517 | 305k | } |
518 | 1.77k | } |
519 | | |
520 | | /* We need to go over 'pred' because it should contain only the |
521 | | edges towards the target vertex. */ |
522 | 308k | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
523 | 306k | igraph_vector_int_t *v = igraph_adjlist_get(&pred, i); |
524 | 306k | igraph_int_t n = igraph_vector_int_size(v); |
525 | 374k | for (igraph_int_t j = 0; j < n; ) { |
526 | 67.6k | igraph_int_t v2 = VECTOR(*v)[j]; |
527 | 67.6k | if (VECTOR(parent)[v2] >= -1) { |
528 | 42.5k | j++; |
529 | 42.5k | } else { |
530 | 25.0k | VECTOR(*v)[j] = VECTOR(*v)[n - 1]; |
531 | 25.0k | igraph_vector_int_pop_back(v); |
532 | 25.0k | n--; |
533 | 25.0k | } |
534 | 67.6k | } |
535 | 306k | } |
536 | | |
537 | | /* Now comes the main algorithm, steps 2 & 3 */ |
538 | | |
539 | 23.8k | for (igraph_int_t i = component_size - 1; i > 0; i--) { |
540 | 22.1k | igraph_int_t w = VECTOR(vertex)[i] - 1; |
541 | 22.1k | igraph_vector_int_t *predw = igraph_adjlist_get(&pred, w); |
542 | 22.1k | igraph_int_t j, n = igraph_vector_int_size(predw); |
543 | 55.1k | for (j = 0; j < n; j++) { |
544 | 33.0k | igraph_int_t v = VECTOR(*predw)[j]; |
545 | 33.0k | igraph_int_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); |
546 | 33.0k | if (VECTOR(semi)[u] < VECTOR(semi)[w]) { |
547 | 22.8k | VECTOR(semi)[w] = VECTOR(semi)[u]; |
548 | 22.8k | } |
549 | 33.0k | } |
550 | 22.1k | igraph_i_dbucket_insert(&bucket, VECTOR(vertex)[ VECTOR(semi)[w] - 1 ] - 1, w); |
551 | 22.1k | igraph_i_dominator_LINK(VECTOR(parent)[w], w, &ancestor); |
552 | 44.2k | while (!igraph_i_dbucket_empty(&bucket, VECTOR(parent)[w])) { |
553 | 22.1k | igraph_int_t v = igraph_i_dbucket_delete(&bucket, VECTOR(parent)[w]); |
554 | 22.1k | igraph_int_t u = igraph_i_dominator_EVAL(v, &ancestor, &label, &semi); |
555 | 22.1k | VECTOR(*mydom)[v] = VECTOR(semi)[u] < VECTOR(semi)[v] ? u : |
556 | 22.1k | VECTOR(parent)[w]; |
557 | 22.1k | } |
558 | 22.1k | } |
559 | | |
560 | | /* Finally, step 4 */ |
561 | | |
562 | 23.8k | for (igraph_int_t i = 1; i < component_size; i++) { |
563 | 22.1k | igraph_int_t w = VECTOR(vertex)[i] - 1; |
564 | 22.1k | if (VECTOR(*mydom)[w] != VECTOR(vertex)[VECTOR(semi)[w] - 1] - 1) { |
565 | 531 | VECTOR(*mydom)[w] = VECTOR(*mydom)[VECTOR(*mydom)[w]]; |
566 | 531 | } |
567 | 22.1k | } |
568 | 1.77k | VECTOR(*mydom)[root] = -1; |
569 | | |
570 | 1.77k | igraph_i_dbucket_destroy(&bucket); |
571 | 1.77k | igraph_adjlist_destroy(&pred); |
572 | 1.77k | igraph_adjlist_destroy(&succ); |
573 | 1.77k | igraph_vector_int_destroy(&label); |
574 | 1.77k | igraph_vector_int_destroy(&ancestor); |
575 | 1.77k | igraph_vector_int_destroy(&vertex); |
576 | 1.77k | igraph_vector_int_destroy(&semi); |
577 | 1.77k | igraph_vector_int_destroy(&parent); |
578 | 1.77k | IGRAPH_FINALLY_CLEAN(8); |
579 | | |
580 | 1.77k | if (domtree) { |
581 | 0 | igraph_vector_int_t edges; |
582 | 0 | igraph_int_t ptr = 0; |
583 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, component_size * 2 - 2); |
584 | 0 | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
585 | 0 | if (i != root && VECTOR(*mydom)[i] >= 0) { |
586 | 0 | if (mode == IGRAPH_OUT) { |
587 | 0 | VECTOR(edges)[ptr++] = VECTOR(*mydom)[i]; |
588 | 0 | VECTOR(edges)[ptr++] = i; |
589 | 0 | } else { |
590 | 0 | VECTOR(edges)[ptr++] = i; |
591 | 0 | VECTOR(edges)[ptr++] = VECTOR(*mydom)[i]; |
592 | 0 | } |
593 | 0 | } |
594 | 0 | } |
595 | 0 | IGRAPH_CHECK(igraph_create(domtree, &edges, no_of_nodes, |
596 | 0 | IGRAPH_DIRECTED)); |
597 | 0 | igraph_vector_int_destroy(&edges); |
598 | 0 | IGRAPH_FINALLY_CLEAN(1); |
599 | |
|
600 | 0 | IGRAPH_CHECK(igraph_i_attribute_copy(domtree, graph, true, true, /*edges=*/ false)); |
601 | 0 | } |
602 | | |
603 | 1.77k | if (!dom) { |
604 | 0 | igraph_vector_int_destroy(&vdom); |
605 | 0 | IGRAPH_FINALLY_CLEAN(1); |
606 | 0 | } |
607 | | |
608 | 1.77k | return IGRAPH_SUCCESS; |
609 | 1.77k | } |
610 | | |
611 | | typedef struct igraph_i_all_st_cuts_minimal_dfs_data_t { |
612 | | igraph_stack_int_t *stack; |
613 | | igraph_bitset_t *nomark; |
614 | | const igraph_bitset_t *GammaX; |
615 | | igraph_int_t root; |
616 | | const igraph_vector_int_t *map; |
617 | | } igraph_i_all_st_cuts_minimal_dfs_data_t; |
618 | | |
619 | | static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_incb( |
620 | | const igraph_t *graph, |
621 | | igraph_int_t vid, |
622 | | igraph_int_t dist, |
623 | 0 | void *extra) { |
624 | |
|
625 | 0 | igraph_i_all_st_cuts_minimal_dfs_data_t *data = extra; |
626 | 0 | igraph_stack_int_t *stack = data->stack; |
627 | 0 | igraph_bitset_t *nomark = data->nomark; |
628 | 0 | const igraph_bitset_t *GammaX = data->GammaX; |
629 | 0 | const igraph_vector_int_t *map = data->map; |
630 | 0 | igraph_int_t realvid = VECTOR(*map)[vid]; |
631 | |
|
632 | 0 | IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist); |
633 | |
|
634 | 0 | if (IGRAPH_BIT_TEST(*GammaX, realvid)) { |
635 | 0 | if (!igraph_stack_int_empty(stack)) { |
636 | 0 | igraph_int_t top = igraph_stack_int_top(stack); |
637 | 0 | IGRAPH_BIT_SET(*nomark, top); /* we just found a smaller one */ |
638 | 0 | } |
639 | 0 | IGRAPH_CHECK(igraph_stack_int_push(stack, realvid)); |
640 | 0 | } |
641 | | |
642 | 0 | return IGRAPH_SUCCESS; |
643 | 0 | } |
644 | | |
645 | | static igraph_error_t igraph_i_all_st_cuts_minimal_dfs_outcb( |
646 | | const igraph_t *graph, |
647 | | igraph_int_t vid, |
648 | | igraph_int_t dist, |
649 | 0 | void *extra) { |
650 | 0 | igraph_i_all_st_cuts_minimal_dfs_data_t *data = extra; |
651 | 0 | igraph_stack_int_t *stack = data->stack; |
652 | 0 | const igraph_vector_int_t *map = data->map; |
653 | 0 | igraph_int_t realvid = VECTOR(*map)[vid]; |
654 | |
|
655 | 0 | IGRAPH_UNUSED(graph); IGRAPH_UNUSED(dist); |
656 | |
|
657 | 0 | if (!igraph_stack_int_empty(stack) && |
658 | 0 | igraph_stack_int_top(stack) == realvid) { |
659 | 0 | igraph_stack_int_pop(stack); |
660 | 0 | } |
661 | |
|
662 | 0 | return IGRAPH_SUCCESS; |
663 | 0 | } |
664 | | |
665 | | static igraph_error_t igraph_i_all_st_cuts_minimal(const igraph_t *graph, |
666 | | const igraph_t *domtree, |
667 | | igraph_int_t root, |
668 | | const igraph_marked_queue_int_t *X, |
669 | | const igraph_bitset_t *GammaX, |
670 | | const igraph_vector_int_t *invmap, |
671 | 0 | igraph_vector_int_t *minimal) { |
672 | |
|
673 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
674 | 0 | igraph_stack_int_t stack; |
675 | 0 | igraph_bitset_t nomark; |
676 | 0 | igraph_i_all_st_cuts_minimal_dfs_data_t data; |
677 | 0 | igraph_int_t i; |
678 | |
|
679 | 0 | IGRAPH_UNUSED(X); |
680 | |
|
681 | 0 | IGRAPH_STACK_INT_INIT_FINALLY(&stack, 10); |
682 | 0 | IGRAPH_BITSET_INIT_FINALLY(&nomark, no_of_nodes); |
683 | | |
684 | 0 | data.stack = &stack; |
685 | 0 | data.nomark = &nomark; |
686 | 0 | data.GammaX = GammaX; |
687 | 0 | data.root = root; |
688 | 0 | data.map = invmap; |
689 | | |
690 | | /* We mark all GammaX elements as minimal first. |
691 | | TODO: actually, we could just use GammaX to return the minimal |
692 | | elements. */ |
693 | 0 | igraph_bitset_not(&nomark, GammaX); |
694 | | |
695 | | /* We do a reverse DFS from root. If, along a path we find a GammaX |
696 | | vertex after (=below) another GammaX vertex, we mark the higher |
697 | | one as non-minimal. */ |
698 | |
|
699 | 0 | IGRAPH_CHECK(igraph_dfs(domtree, root, IGRAPH_IN, |
700 | 0 | /*unreachable=*/ false, /*order=*/ NULL, |
701 | 0 | /*order_out=*/ NULL, /*parents=*/ NULL, |
702 | 0 | /*dist=*/ NULL, |
703 | 0 | /*in_callback=*/ igraph_i_all_st_cuts_minimal_dfs_incb, |
704 | 0 | /*out_callback=*/ igraph_i_all_st_cuts_minimal_dfs_outcb, |
705 | 0 | /*extra=*/ &data)); |
706 | | |
707 | 0 | igraph_vector_int_clear(minimal); |
708 | 0 | for (i = 0; i < no_of_nodes; i++) { |
709 | 0 | if (!IGRAPH_BIT_TEST(nomark, i)) { |
710 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(minimal, i)); |
711 | 0 | } |
712 | 0 | } |
713 | | |
714 | 0 | igraph_bitset_destroy(&nomark); |
715 | 0 | igraph_stack_int_destroy(&stack); |
716 | 0 | IGRAPH_FINALLY_CLEAN(2); |
717 | |
|
718 | 0 | return IGRAPH_SUCCESS; |
719 | 0 | } |
720 | | |
721 | | /* not 'static' because used in igraph_all_st_cuts.c test program */ |
722 | | igraph_error_t igraph_i_all_st_cuts_pivot( |
723 | | const igraph_t *graph, const igraph_marked_queue_int_t *S, |
724 | | const igraph_estack_t *T, igraph_int_t source, igraph_int_t target, |
725 | | igraph_int_t *v, igraph_vector_int_t *Isv, void *arg |
726 | 0 | ) { |
727 | |
|
728 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
729 | 0 | igraph_t Sbar; |
730 | 0 | igraph_vector_int_t Sbar_map, Sbar_invmap; |
731 | 0 | igraph_vector_int_t keep; |
732 | 0 | igraph_t domtree; |
733 | 0 | igraph_vector_int_t leftout; |
734 | 0 | igraph_int_t i, nomin, n; |
735 | 0 | igraph_int_t root; |
736 | 0 | igraph_vector_int_t M; |
737 | 0 | igraph_bitset_t GammaS; |
738 | 0 | igraph_vector_int_t Nuv; |
739 | 0 | igraph_vector_int_t Isv_min; |
740 | 0 | igraph_vector_int_t GammaS_vec; |
741 | 0 | igraph_int_t Sbar_size; |
742 | |
|
743 | 0 | IGRAPH_UNUSED(arg); |
744 | | |
745 | | /* We need to create the graph induced by Sbar */ |
746 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Sbar_map, 0); |
747 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Sbar_invmap, 0); |
748 | | |
749 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&keep, 0); |
750 | 0 | for (i = 0; i < no_of_nodes; i++) { |
751 | 0 | if (!igraph_marked_queue_int_iselement(S, i)) { |
752 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&keep, i)); |
753 | 0 | } |
754 | 0 | } |
755 | 0 | Sbar_size = igraph_vector_int_size(&keep); |
756 | |
|
757 | 0 | IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &Sbar, |
758 | 0 | igraph_vss_vector(&keep), |
759 | 0 | IGRAPH_SUBGRAPH_AUTO, |
760 | 0 | /* map= */ &Sbar_map, |
761 | 0 | /* invmap= */ &Sbar_invmap)); |
762 | 0 | igraph_vector_int_destroy(&keep); |
763 | 0 | IGRAPH_FINALLY_CLEAN(1); |
764 | 0 | IGRAPH_FINALLY(igraph_destroy, &Sbar); |
765 | |
|
766 | 0 | root = VECTOR(Sbar_map)[target]; |
767 | | |
768 | | /* -------------------------------------------------------------*/ |
769 | | /* Construct the dominator tree of Sbar */ |
770 | |
|
771 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&leftout, 0); |
772 | 0 | IGRAPH_CHECK(igraph_dominator_tree(&Sbar, root, |
773 | 0 | /*dom=*/ 0, &domtree, |
774 | 0 | &leftout, IGRAPH_IN)); |
775 | 0 | IGRAPH_FINALLY(igraph_destroy, &domtree); |
776 | | |
777 | | /* -------------------------------------------------------------*/ |
778 | | /* Identify the set M of minimal elements of Gamma(S) with respect |
779 | | to the dominator relation. */ |
780 | | |
781 | | /* First we create GammaS */ |
782 | | /* TODO: use the adjacency list, instead of neighbors() */ |
783 | 0 | IGRAPH_BITSET_INIT_FINALLY(&GammaS, no_of_nodes); |
784 | 0 | if (igraph_marked_queue_int_size(S) == 0) { |
785 | 0 | IGRAPH_BIT_SET(GammaS, VECTOR(Sbar_map)[source]); |
786 | 0 | } else { |
787 | 0 | for (i = 0; i < no_of_nodes; i++) { |
788 | 0 | if (igraph_marked_queue_int_iselement(S, i)) { |
789 | 0 | igraph_vector_int_t neis; |
790 | 0 | igraph_int_t j; |
791 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); |
792 | 0 | IGRAPH_CHECK(igraph_neighbors( |
793 | 0 | graph, &neis, i, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE |
794 | 0 | )); |
795 | 0 | n = igraph_vector_int_size(&neis); |
796 | 0 | for (j = 0; j < n; j++) { |
797 | 0 | igraph_int_t nei = VECTOR(neis)[j]; |
798 | 0 | if (!igraph_marked_queue_int_iselement(S, nei)) { |
799 | 0 | IGRAPH_BIT_SET(GammaS, nei); |
800 | 0 | } |
801 | 0 | } |
802 | 0 | igraph_vector_int_destroy(&neis); |
803 | 0 | IGRAPH_FINALLY_CLEAN(1); |
804 | 0 | } |
805 | 0 | } |
806 | 0 | } |
807 | | |
808 | | /* Relabel left out vertices (set K in Provan & Shier) to |
809 | | correspond to node labelling of graph instead of SBar. |
810 | | At the same time ensure that GammaS is a proper subset of |
811 | | L, where L are the nodes in the dominator tree. */ |
812 | 0 | n = igraph_vector_int_size(&leftout); |
813 | 0 | for (i = 0; i < n; i++) { |
814 | 0 | VECTOR(leftout)[i] = VECTOR(Sbar_invmap)[VECTOR(leftout)[i]]; |
815 | 0 | IGRAPH_BIT_CLEAR(GammaS, VECTOR(leftout)[i]); |
816 | 0 | } |
817 | |
|
818 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&M, 0); |
819 | 0 | if (igraph_ecount(&domtree) > 0) { |
820 | 0 | IGRAPH_CHECK(igraph_i_all_st_cuts_minimal(graph, &domtree, root, S, |
821 | 0 | &GammaS, &Sbar_invmap, &M)); |
822 | 0 | } |
823 | | |
824 | 0 | igraph_vector_int_clear(Isv); |
825 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Nuv, 0); |
826 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Isv_min, 0); |
827 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&GammaS_vec, 0); |
828 | 0 | for (i = 0; i < no_of_nodes; i++) { |
829 | 0 | if (IGRAPH_BIT_TEST(GammaS, i)) { |
830 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&GammaS_vec, i)); |
831 | 0 | } |
832 | 0 | } |
833 | | |
834 | 0 | nomin = igraph_vector_int_size(&M); |
835 | 0 | for (i = 0; i < nomin; i++) { |
836 | | /* -------------------------------------------------------------*/ |
837 | | /* For each v in M find the set Nu(v)=dom(Sbar, v)-K |
838 | | Nu(v) contains all vertices that are dominated by v, for every |
839 | | v, this is a subtree of the dominator tree, rooted at v. The |
840 | | different subtrees are disjoint. */ |
841 | 0 | igraph_int_t min = VECTOR(Sbar_map)[ VECTOR(M)[i] ]; |
842 | 0 | igraph_int_t nuvsize, isvlen, j; |
843 | 0 | IGRAPH_CHECK(igraph_dfs(&domtree, min, IGRAPH_IN, |
844 | 0 | /*unreachable=*/ false, /*order=*/ &Nuv, |
845 | 0 | /*order_out=*/ NULL, /*parents=*/ NULL, /*dist=*/ NULL, |
846 | 0 | /*in_callback=*/ NULL, /*out_callback=*/ NULL, |
847 | 0 | /*extra=*/ NULL)); |
848 | | /* Remove the negative values from the end of the vector */ |
849 | 0 | for (nuvsize = 0; nuvsize < Sbar_size; nuvsize++) { |
850 | 0 | igraph_int_t t = VECTOR(Nuv)[nuvsize]; |
851 | 0 | if (t >= 0) { |
852 | 0 | VECTOR(Nuv)[nuvsize] = VECTOR(Sbar_invmap)[t]; |
853 | 0 | } else { |
854 | 0 | break; |
855 | 0 | } |
856 | 0 | } |
857 | 0 | igraph_vector_int_resize(&Nuv, nuvsize); /* shrinks, error safe */ |
858 | | |
859 | | /* -------------------------------------------------------------*/ |
860 | | /* By a BFS search of <Nu(v)> determine I(S,v)-K. |
861 | | I(S,v) contains all vertices that are in Nu(v) and that are |
862 | | reachable from Gamma(S) via a path in Nu(v). */ |
863 | 0 | IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ -1, /*roots=*/ &GammaS_vec, |
864 | 0 | /*mode=*/ IGRAPH_OUT, /*unreachable=*/ false, |
865 | 0 | /*restricted=*/ &Nuv, |
866 | 0 | /*order=*/ &Isv_min, /*rank=*/ NULL, |
867 | 0 | /*parents=*/ NULL, /*pred=*/ NULL, /*succ=*/ NULL, |
868 | 0 | /*dist=*/ NULL, /*callback=*/ NULL, /*extra=*/ NULL)); |
869 | 0 | for (isvlen = 0; isvlen < no_of_nodes; isvlen++) { |
870 | 0 | if (VECTOR(Isv_min)[isvlen] < 0) { |
871 | 0 | break; |
872 | 0 | } |
873 | 0 | } |
874 | 0 | igraph_vector_int_resize(&Isv_min, isvlen); |
875 | | |
876 | | /* -------------------------------------------------------------*/ |
877 | | /* For each c in M check whether Isv-K is included in Tbar. If |
878 | | such a v is found, compute Isv={x|v[Nu(v) U K]x} and return v and |
879 | | Isv; otherwise return Isv={}. */ |
880 | 0 | for (j = 0; j < isvlen; j++) { |
881 | 0 | igraph_int_t u = VECTOR(Isv_min)[j]; |
882 | 0 | if (igraph_estack_iselement(T, u) || u == target) { |
883 | 0 | break; |
884 | 0 | } |
885 | 0 | } |
886 | | /* We might have found one */ |
887 | 0 | if (j == isvlen) { |
888 | 0 | *v = VECTOR(M)[i]; |
889 | | /* Calculate real Isv */ |
890 | 0 | IGRAPH_CHECK(igraph_vector_int_append(&Nuv, &leftout)); |
891 | 0 | IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ *v, |
892 | 0 | /*roots=*/ NULL, /*mode=*/ IGRAPH_OUT, |
893 | 0 | /*unreachable=*/ false, /*restricted=*/ &Nuv, |
894 | 0 | /*order=*/ &Isv_min, /*rank=*/ NULL, |
895 | 0 | /*parents=*/ NULL, /*pred=*/ NULL, /*succ=*/ NULL, |
896 | 0 | /*dist=*/ NULL, /*callback=*/ NULL, /*extra=*/ NULL)); |
897 | 0 | for (isvlen = 0; isvlen < no_of_nodes; isvlen++) { |
898 | 0 | if (VECTOR(Isv_min)[isvlen] < 0) { |
899 | 0 | break; |
900 | 0 | } |
901 | 0 | } |
902 | 0 | igraph_vector_int_resize(&Isv_min, isvlen); |
903 | 0 | igraph_vector_int_update(Isv, &Isv_min); |
904 | |
|
905 | 0 | break; |
906 | 0 | } |
907 | 0 | } |
908 | | |
909 | 0 | igraph_vector_int_destroy(&GammaS_vec); |
910 | 0 | igraph_vector_int_destroy(&Isv_min); |
911 | 0 | igraph_vector_int_destroy(&Nuv); |
912 | 0 | IGRAPH_FINALLY_CLEAN(3); |
913 | |
|
914 | 0 | igraph_vector_int_destroy(&M); |
915 | 0 | igraph_bitset_destroy(&GammaS); |
916 | 0 | igraph_destroy(&domtree); |
917 | 0 | igraph_vector_int_destroy(&leftout); |
918 | 0 | igraph_destroy(&Sbar); |
919 | 0 | igraph_vector_int_destroy(&Sbar_map); |
920 | 0 | igraph_vector_int_destroy(&Sbar_invmap); |
921 | 0 | IGRAPH_FINALLY_CLEAN(7); |
922 | |
|
923 | 0 | return IGRAPH_SUCCESS; |
924 | 0 | } |
925 | | |
926 | | /* TODO: This is a temporary recursive version */ |
927 | | |
928 | | static igraph_error_t igraph_i_provan_shier_list_recursive( |
929 | | const igraph_t *graph, igraph_marked_queue_int_t *S, |
930 | | igraph_estack_t *T, igraph_int_t source, igraph_int_t target, |
931 | | igraph_vector_int_list_t *result, igraph_provan_shier_pivot_t *pivot, |
932 | | igraph_vector_int_t *Isv, void *pivot_arg |
933 | 0 | ) { |
934 | |
|
935 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
936 | 0 | igraph_int_t v = 0; |
937 | 0 | igraph_int_t i, n; |
938 | |
|
939 | 0 | pivot(graph, S, T, source, target, &v, Isv, pivot_arg); |
940 | |
|
941 | 0 | if (igraph_vector_int_empty(Isv)) { |
942 | 0 | if (igraph_marked_queue_int_size(S) != 0 && igraph_marked_queue_int_size(S) != no_of_nodes) { |
943 | 0 | igraph_vector_int_t *vec; |
944 | 0 | IGRAPH_CHECK(igraph_vector_int_list_push_back_new(result, &vec)); |
945 | 0 | IGRAPH_CHECK(igraph_marked_queue_int_as_vector(S, vec)); |
946 | 0 | } |
947 | 0 | } else { |
948 | | /* Add Isv to S */ |
949 | 0 | IGRAPH_CHECK(igraph_marked_queue_int_start_batch(S)); |
950 | 0 | n = igraph_vector_int_size(Isv); |
951 | 0 | for (i = 0; i < n; i++) { |
952 | 0 | if (!igraph_marked_queue_int_iselement(S, VECTOR(*Isv)[i])) { |
953 | 0 | IGRAPH_CHECK(igraph_marked_queue_int_push(S, VECTOR(*Isv)[i])); |
954 | 0 | } |
955 | 0 | } |
956 | 0 | igraph_vector_int_clear(Isv); |
957 | | |
958 | | /* Go down right in the search tree */ |
959 | 0 | IGRAPH_CHECK(igraph_i_provan_shier_list_recursive( |
960 | 0 | graph, S, T, source, target, result, pivot, Isv, pivot_arg)); |
961 | | |
962 | | /* Take out Isv from S */ |
963 | 0 | igraph_marked_queue_int_pop_back_batch(S); |
964 | | |
965 | | /* Put v into T */ |
966 | 0 | IGRAPH_CHECK(igraph_estack_push(T, v)); |
967 | | |
968 | | /* Go down left in the search tree */ |
969 | 0 | IGRAPH_CHECK(igraph_i_provan_shier_list_recursive( |
970 | 0 | graph, S, T, source, target, result, pivot, Isv, pivot_arg)); |
971 | | |
972 | | /* Take out v from T */ |
973 | 0 | igraph_estack_pop(T); |
974 | |
|
975 | 0 | } |
976 | | |
977 | 0 | return IGRAPH_SUCCESS; |
978 | 0 | } |
979 | | |
980 | | static igraph_error_t igraph_provan_shier_list( |
981 | | const igraph_t *graph, igraph_marked_queue_int_t *S, |
982 | | igraph_estack_t *T, igraph_int_t source, igraph_int_t target, |
983 | | igraph_vector_int_list_t *result, igraph_provan_shier_pivot_t *pivot, |
984 | | void *pivot_arg |
985 | 0 | ) { |
986 | 0 | igraph_vector_int_t Isv; |
987 | |
|
988 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Isv, 0); |
989 | | |
990 | 0 | IGRAPH_CHECK(igraph_i_provan_shier_list_recursive( |
991 | 0 | graph, S, T, source, target, result, pivot, &Isv, pivot_arg |
992 | 0 | )); |
993 | | |
994 | | /* Reverse the result to stay compatible with versions before 0.10.3 */ |
995 | 0 | IGRAPH_CHECK(igraph_vector_int_list_reverse(result)); |
996 | | |
997 | 0 | igraph_vector_int_destroy(&Isv); |
998 | 0 | IGRAPH_FINALLY_CLEAN(1); |
999 | |
|
1000 | 0 | return IGRAPH_SUCCESS; |
1001 | 0 | } |
1002 | | |
1003 | | /** |
1004 | | * \function igraph_all_st_cuts |
1005 | | * List all edge-cuts between two vertices in a directed graph |
1006 | | * |
1007 | | * This function lists all edge-cuts between a source and a target |
1008 | | * vertex. Every cut is listed exactly once. The implemented algorithm |
1009 | | * is described in JS Provan and DR Shier: A Paradigm for listing |
1010 | | * (s,t)-cuts in graphs, Algorithmica 15, 351--372, 1996. |
1011 | | * |
1012 | | * \param graph The input graph, is must be directed. |
1013 | | * \param cuts An initialized list of integer vectors, the cuts are stored |
1014 | | * here. Each vector will contain the IDs of the edges in |
1015 | | * the cut. This argument is ignored if it is a null pointer. |
1016 | | * \param partition1s An initialized list of integer vectors, the list of |
1017 | | * vertex sets generating the actual edge cuts are stored |
1018 | | * here. Each vector contains a set of vertex IDs. If X is such |
1019 | | * a set, then all edges going from X to the complement of X |
1020 | | * form an (s, t) edge-cut in the graph. This argument is |
1021 | | * ignored if it is a null pointer. |
1022 | | * \param source The id of the source vertex. |
1023 | | * \param target The id of the target vertex. |
1024 | | * \return Error code. |
1025 | | * |
1026 | | * Time complexity: O(n(|V|+|E|)), where |V| is the number of |
1027 | | * vertices, |E| is the number of edges, and n is the number of cuts. |
1028 | | */ |
1029 | | |
1030 | | igraph_error_t igraph_all_st_cuts(const igraph_t *graph, |
1031 | | igraph_vector_int_list_t *cuts, |
1032 | | igraph_vector_int_list_t *partition1s, |
1033 | | igraph_int_t source, |
1034 | 0 | igraph_int_t target) { |
1035 | | |
1036 | | /* S is a special stack, in which elements are pushed in batches. |
1037 | | It is then possible to remove the whole batch in one step. |
1038 | | |
1039 | | T is a stack with an is-element operation. |
1040 | | Every element is included at most once. |
1041 | | */ |
1042 | |
|
1043 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1044 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
1045 | 0 | igraph_marked_queue_int_t S; |
1046 | 0 | igraph_estack_t T; |
1047 | 0 | igraph_vector_int_list_t *mypartition1s = partition1s, vpartition1s; |
1048 | 0 | igraph_vector_int_t cut; |
1049 | 0 | igraph_int_t i, nocuts; |
1050 | |
|
1051 | 0 | if (!igraph_is_directed(graph)) { |
1052 | 0 | IGRAPH_ERROR("Listing all s-t cuts only implemented for " |
1053 | 0 | "directed graphs", IGRAPH_UNIMPLEMENTED); |
1054 | 0 | } |
1055 | | |
1056 | 0 | if (!partition1s) { |
1057 | 0 | mypartition1s = &vpartition1s; |
1058 | 0 | IGRAPH_CHECK(igraph_vector_int_list_init(mypartition1s, 0)); |
1059 | 0 | IGRAPH_FINALLY(igraph_vector_int_list_destroy, mypartition1s); |
1060 | 0 | } else { |
1061 | 0 | igraph_vector_int_list_clear(mypartition1s); |
1062 | 0 | } |
1063 | | |
1064 | 0 | IGRAPH_CHECK(igraph_marked_queue_int_init(&S, no_of_nodes)); |
1065 | 0 | IGRAPH_FINALLY(igraph_marked_queue_int_destroy, &S); |
1066 | 0 | IGRAPH_CHECK(igraph_estack_init(&T, no_of_nodes, 0)); |
1067 | 0 | IGRAPH_FINALLY(igraph_estack_destroy, &T); |
1068 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&cut, 0); |
1069 | | |
1070 | | /* We call it with S={}, T={} */ |
1071 | 0 | IGRAPH_CHECK(igraph_provan_shier_list(graph, &S, &T, |
1072 | 0 | source, target, mypartition1s, |
1073 | 0 | igraph_i_all_st_cuts_pivot, |
1074 | 0 | /*pivot_arg=*/ 0)); |
1075 | | |
1076 | 0 | nocuts = igraph_vector_int_list_size(mypartition1s); |
1077 | |
|
1078 | 0 | if (cuts) { |
1079 | 0 | igraph_vector_int_t inS; |
1080 | 0 | IGRAPH_CHECK(igraph_vector_int_init(&inS, no_of_nodes)); |
1081 | 0 | IGRAPH_FINALLY(igraph_vector_int_destroy, &inS); |
1082 | 0 | igraph_vector_int_list_clear(cuts); |
1083 | 0 | IGRAPH_CHECK(igraph_vector_int_list_reserve(cuts, nocuts)); |
1084 | 0 | for (i = 0; i < nocuts; i++) { |
1085 | 0 | igraph_vector_int_t *part = igraph_vector_int_list_get_ptr(mypartition1s, i); |
1086 | 0 | igraph_int_t cutsize = 0; |
1087 | 0 | igraph_int_t j, partlen = igraph_vector_int_size(part); |
1088 | | /* Mark elements */ |
1089 | 0 | for (j = 0; j < partlen; j++) { |
1090 | 0 | igraph_int_t v = VECTOR(*part)[j]; |
1091 | 0 | VECTOR(inS)[v] = i + 1; |
1092 | 0 | } |
1093 | | /* Check how many edges */ |
1094 | 0 | for (j = 0; j < no_of_edges; j++) { |
1095 | 0 | igraph_int_t from = IGRAPH_FROM(graph, j); |
1096 | 0 | igraph_int_t to = IGRAPH_TO(graph, j); |
1097 | 0 | igraph_int_t pfrom = VECTOR(inS)[from]; |
1098 | 0 | igraph_int_t pto = VECTOR(inS)[to]; |
1099 | 0 | if (pfrom == i + 1 && pto != i + 1) { |
1100 | 0 | cutsize++; |
1101 | 0 | } |
1102 | 0 | } |
1103 | | /* Add the edges */ |
1104 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(&cut, cutsize)); |
1105 | 0 | cutsize = 0; |
1106 | 0 | for (j = 0; j < no_of_edges; j++) { |
1107 | 0 | igraph_int_t from = IGRAPH_FROM(graph, j); |
1108 | 0 | igraph_int_t to = IGRAPH_TO(graph, j); |
1109 | 0 | igraph_int_t pfrom = VECTOR(inS)[from]; |
1110 | 0 | igraph_int_t pto = VECTOR(inS)[to]; |
1111 | 0 | if ((pfrom == i + 1 && pto != i + 1)) { |
1112 | 0 | VECTOR(cut)[cutsize++] = j; |
1113 | 0 | } |
1114 | 0 | } |
1115 | | /* Add the vector to 'cuts' */ |
1116 | 0 | IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(cuts, &cut)); |
1117 | 0 | } |
1118 | | |
1119 | 0 | igraph_vector_int_destroy(&inS); |
1120 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1121 | 0 | } |
1122 | | |
1123 | 0 | igraph_vector_int_destroy(&cut); |
1124 | 0 | igraph_estack_destroy(&T); |
1125 | 0 | igraph_marked_queue_int_destroy(&S); |
1126 | 0 | IGRAPH_FINALLY_CLEAN(3); |
1127 | |
|
1128 | 0 | if (!partition1s) { |
1129 | 0 | igraph_vector_int_list_destroy(mypartition1s); |
1130 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1131 | 0 | } |
1132 | |
|
1133 | 0 | return IGRAPH_SUCCESS; |
1134 | 0 | } |
1135 | | |
1136 | | /* We need to find the minimal active elements of Sbar. I.e. all |
1137 | | active Sbar elements 'v', s.t. there is no other 'w' active Sbar |
1138 | | element from which 'v' is reachable. (Not necessarily through |
1139 | | active vertices.) |
1140 | | |
1141 | | We do so by traversing the nodes in topological sort order. The nodes that |
1142 | | are processed first and are not yet connected to any minimal nodes are then |
1143 | | marked as minimal (if active). Any subsequent nodes that are connected to |
1144 | | minimal nodes are then not marked as minimal. |
1145 | | */ |
1146 | | |
1147 | | static igraph_error_t igraph_i_all_st_mincuts_minimal(const igraph_t *residual, |
1148 | | const igraph_marked_queue_int_t *S, |
1149 | | const igraph_bitset_t *active, |
1150 | 0 | igraph_vector_int_t *minimal) { |
1151 | |
|
1152 | 0 | igraph_int_t no_of_nodes = igraph_vcount(residual); |
1153 | 0 | igraph_int_t i; |
1154 | 0 | igraph_vector_int_t neis; |
1155 | 0 | igraph_bitset_t connected_to_minimal; |
1156 | |
|
1157 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); |
1158 | 0 | IGRAPH_BITSET_INIT_FINALLY(&connected_to_minimal, no_of_nodes); |
1159 | | |
1160 | | // Clear minimal nodes, we will push back to vector as required. |
1161 | 0 | igraph_vector_int_clear(minimal); |
1162 | | |
1163 | | /* We will loop over the nodes in topological sort order, where residual is |
1164 | | * assumed to already be in topological sort order. This way, any node that |
1165 | | * we encounter that is not yet connected to a minimal node and that is |
1166 | | * active, should be marked as minimal. Any node that is connected to a |
1167 | | * minimal node should not be considered minimal, irrespective of it being |
1168 | | * active or not. |
1169 | | */ |
1170 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1171 | 0 | igraph_int_t j, n; |
1172 | 0 | IGRAPH_CHECK(igraph_neighbors( |
1173 | 0 | residual, &neis, i, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_MULTIPLE |
1174 | 0 | )); |
1175 | 0 | n = igraph_vector_int_size(&neis); |
1176 | | |
1177 | | // Only consider nodes that are not in S. |
1178 | 0 | if (!igraph_marked_queue_int_iselement(S, i)) { |
1179 | 0 | for (j = 0; j < n; j++) { |
1180 | 0 | igraph_int_t nei = VECTOR(neis)[j]; |
1181 | | /* If connected to node that is connected to node that is minimal, |
1182 | | * this node is also connected to node that is minimal. |
1183 | | */ |
1184 | 0 | if (IGRAPH_BIT_TEST(connected_to_minimal, nei)) { |
1185 | 0 | IGRAPH_BIT_SET(connected_to_minimal, i); |
1186 | 0 | break; |
1187 | 0 | } |
1188 | 0 | } |
1189 | | |
1190 | | /* If this node is not connected to node that is minimal, and this node |
1191 | | * is minimal and active itself, set it as a minimal node. |
1192 | | */ |
1193 | 0 | if (!IGRAPH_BIT_TEST(connected_to_minimal, i) && IGRAPH_BIT_TEST(*active, i)) { |
1194 | |
|
1195 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(minimal, i)); |
1196 | | /* Also mark this node as connected to minimal, to make sure that |
1197 | | * any descendants will be marked as being connected to a minimal |
1198 | | * node. |
1199 | | */ |
1200 | 0 | IGRAPH_BIT_SET(connected_to_minimal, i); |
1201 | 0 | } |
1202 | 0 | } |
1203 | 0 | } |
1204 | | |
1205 | 0 | igraph_bitset_destroy(&connected_to_minimal); |
1206 | 0 | igraph_vector_int_destroy(&neis); |
1207 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1208 | |
|
1209 | 0 | return IGRAPH_SUCCESS; |
1210 | 0 | } |
1211 | | |
1212 | | typedef struct igraph_i_all_st_mincuts_data_t { |
1213 | | const igraph_bitset_t *active; |
1214 | | } igraph_i_all_st_mincuts_data_t; |
1215 | | |
1216 | | static igraph_error_t igraph_i_all_st_mincuts_pivot(const igraph_t *graph, |
1217 | | const igraph_marked_queue_int_t *S, |
1218 | | const igraph_estack_t *T, |
1219 | | igraph_int_t source, |
1220 | | igraph_int_t target, |
1221 | | igraph_int_t *v, |
1222 | | igraph_vector_int_t *Isv, |
1223 | 0 | void *arg) { |
1224 | |
|
1225 | 0 | igraph_i_all_st_mincuts_data_t *data = arg; |
1226 | 0 | const igraph_bitset_t *active = data->active; |
1227 | |
|
1228 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1229 | 0 | igraph_int_t i, j; |
1230 | 0 | igraph_vector_int_t keep; |
1231 | 0 | igraph_vector_int_t M; |
1232 | 0 | igraph_int_t nomin; |
1233 | |
|
1234 | 0 | IGRAPH_UNUSED(source); IGRAPH_UNUSED(target); |
1235 | |
|
1236 | 0 | if (igraph_marked_queue_int_size(S) == no_of_nodes) { |
1237 | 0 | igraph_vector_int_clear(Isv); |
1238 | 0 | return IGRAPH_SUCCESS; |
1239 | 0 | } |
1240 | | |
1241 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&keep, 0); |
1242 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1243 | 0 | if (!igraph_marked_queue_int_iselement(S, i)) { |
1244 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&keep, i)); |
1245 | 0 | } |
1246 | 0 | } |
1247 | | |
1248 | | /* ------------------------------------------------------------- */ |
1249 | | /* Identify the set M of minimal elements that are active */ |
1250 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&M, 0); |
1251 | 0 | IGRAPH_CHECK(igraph_i_all_st_mincuts_minimal(graph, S, active, &M)); |
1252 | | |
1253 | | /* ------------------------------------------------------------- */ |
1254 | | /* Now find a minimal element that is not in T */ |
1255 | 0 | igraph_vector_int_clear(Isv); |
1256 | 0 | nomin = igraph_vector_int_size(&M); |
1257 | 0 | for (i = 0; i < nomin; i++) { |
1258 | 0 | igraph_int_t min = VECTOR(M)[i]; |
1259 | 0 | if (min != target) |
1260 | 0 | if (!igraph_estack_iselement(T, min)) { |
1261 | 0 | break; |
1262 | 0 | } |
1263 | 0 | } |
1264 | 0 | if (i != nomin) { |
1265 | | /* OK, we found a pivot element. I(S,v) contains all elements |
1266 | | that can reach the pivot element */ |
1267 | 0 | igraph_vector_int_t Isv_min; |
1268 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&Isv_min, 0); |
1269 | 0 | *v = VECTOR(M)[i]; |
1270 | | /* TODO: restricted == keep ? */ |
1271 | 0 | IGRAPH_CHECK(igraph_bfs(graph, /*root=*/ *v, /*roots=*/ NULL, |
1272 | 0 | /*mode=*/ IGRAPH_IN, /*unreachable=*/ false, |
1273 | 0 | /*restricted=*/ &keep, /*order=*/ &Isv_min, |
1274 | 0 | /*rank=*/ NULL, /*parents=*/ NULL, /*pred=*/ NULL, |
1275 | 0 | /*succ=*/ NULL, /*dist=*/ NULL, /*callback=*/ NULL, |
1276 | 0 | /*extra=*/ NULL)); |
1277 | 0 | for (j = 0; j < no_of_nodes; j++) { |
1278 | 0 | igraph_int_t u = VECTOR(Isv_min)[j]; |
1279 | 0 | if (u < 0) { |
1280 | 0 | break; |
1281 | 0 | } |
1282 | 0 | if (!igraph_marked_queue_int_iselement(S, u)) { |
1283 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(Isv, u)); |
1284 | 0 | } |
1285 | 0 | } |
1286 | 0 | igraph_vector_int_destroy(&Isv_min); |
1287 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1288 | 0 | } |
1289 | | |
1290 | 0 | igraph_vector_int_destroy(&M); |
1291 | 0 | igraph_vector_int_destroy(&keep); |
1292 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1293 | |
|
1294 | 0 | return IGRAPH_SUCCESS; |
1295 | 0 | } |
1296 | | |
1297 | | /** |
1298 | | * \function igraph_all_st_mincuts |
1299 | | * \brief All minimum s-t cuts of a directed graph. |
1300 | | * |
1301 | | * This function lists all edge cuts between two vertices, in a directed graph, |
1302 | | * with minimum total capacity. Possibly, multiple cuts may have the same total |
1303 | | * capacity, although there is often only one minimum cut in weighted graphs. |
1304 | | * It is recommended to supply integer-values capacities. Otherwise, not all |
1305 | | * minimum cuts may be detected because of numerical roundoff errors. |
1306 | | * The implemented algorithm is described in JS Provan and DR |
1307 | | * Shier: A Paradigm for listing (s,t)-cuts in graphs, Algorithmica 15, |
1308 | | * 351--372, 1996. |
1309 | | * |
1310 | | * \param graph The input graph, it must be directed. |
1311 | | * \param value Pointer to a real number or \c NULL. The value of the minimum cut |
1312 | | * is stored here, unless it is a null pointer. |
1313 | | * \param cuts Pointer to initialized list of integer vectors or \c NULL. |
1314 | | * The cuts are stored here as lists of vertex IDs. |
1315 | | * \param partition1s Pointer to an initialized list of integer vectors or \c NULL. |
1316 | | * The list of vertex sets, generating the actual edge cuts, are stored |
1317 | | * here. Each vector contains a set of vertex IDs. If X is such |
1318 | | * a set, then all edges going from X to the complement of X |
1319 | | * form an (s,t) edge-cut in the graph. |
1320 | | * \param source The id of the source vertex. |
1321 | | * \param target The id of the target vertex. |
1322 | | * \param capacity Vector of edge capacities. All capacities must be |
1323 | | * strictly positive. If this is a null pointer, then all edges |
1324 | | * are assumed to have capacity one. |
1325 | | * \return Error code. |
1326 | | * |
1327 | | * Time complexity: O(n(|V|+|E|))+O(F), where |V| is the number of |
1328 | | * vertices, |E| is the number of edges, and n is the number of cuts; |
1329 | | * O(F) is the time complexity of the maximum flow algorithm, see \ref |
1330 | | * igraph_maxflow(). |
1331 | | * |
1332 | | * \example examples/simple/igraph_all_st_mincuts.c |
1333 | | */ |
1334 | | |
1335 | | igraph_error_t igraph_all_st_mincuts(const igraph_t *graph, igraph_real_t *value, |
1336 | | igraph_vector_int_list_t *cuts, |
1337 | | igraph_vector_int_list_t *partition1s, |
1338 | | igraph_int_t source, |
1339 | | igraph_int_t target, |
1340 | 0 | const igraph_vector_t *capacity) { |
1341 | |
|
1342 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1343 | 0 | igraph_int_t no_of_edges = igraph_ecount(graph); |
1344 | 0 | igraph_vector_t flow; |
1345 | 0 | igraph_t residual; |
1346 | 0 | igraph_vector_int_t NtoL; |
1347 | 0 | igraph_vector_int_t cut; |
1348 | 0 | igraph_int_t newsource, newtarget; |
1349 | 0 | igraph_marked_queue_int_t S; |
1350 | 0 | igraph_estack_t T; |
1351 | 0 | igraph_i_all_st_mincuts_data_t pivot_data; |
1352 | 0 | igraph_bitset_t VE1bool; |
1353 | 0 | igraph_int_t i, nocuts; |
1354 | 0 | igraph_int_t proj_nodes; |
1355 | 0 | igraph_vector_int_t revmap_ptr, revmap_next; |
1356 | 0 | igraph_vector_int_list_t closedsets; |
1357 | 0 | igraph_vector_int_list_t *mypartition1s = partition1s, vpartition1s; |
1358 | 0 | igraph_maxflow_stats_t stats; |
1359 | | |
1360 | | /* -------------------------------------------------------------------- */ |
1361 | | /* Error checks */ |
1362 | 0 | if (!igraph_is_directed(graph)) { |
1363 | 0 | IGRAPH_ERROR("s-t cuts can only be listed in directed graphs.", IGRAPH_UNIMPLEMENTED); |
1364 | 0 | } |
1365 | 0 | if (source < 0 || source >= no_of_nodes) { |
1366 | 0 | IGRAPH_ERROR("Invalid source vertex.", IGRAPH_EINVVID); |
1367 | 0 | } |
1368 | 0 | if (target < 0 || target >= no_of_nodes) { |
1369 | 0 | IGRAPH_ERROR("Invalid target vertex.", IGRAPH_EINVVID); |
1370 | 0 | } |
1371 | 0 | if (source == target) { |
1372 | 0 | IGRAPH_ERROR("Source and target vertices are the same.", IGRAPH_EINVAL); |
1373 | 0 | } |
1374 | 0 | if (capacity && igraph_vector_size(capacity) != no_of_edges) { |
1375 | 0 | IGRAPH_ERROR("Capacity vector length must agree with number of edges.", IGRAPH_EINVAL); |
1376 | 0 | } |
1377 | 0 | if (capacity && no_of_edges > 0 && igraph_vector_min(capacity) <= 0) { |
1378 | 0 | IGRAPH_ERROR("Not all capacities are strictly positive.", IGRAPH_EINVAL); |
1379 | 0 | } |
1380 | | |
1381 | 0 | if (!partition1s) { |
1382 | 0 | mypartition1s = &vpartition1s; |
1383 | 0 | IGRAPH_CHECK(igraph_vector_int_list_init(mypartition1s, 0)); |
1384 | 0 | IGRAPH_FINALLY(igraph_vector_int_list_destroy, mypartition1s); |
1385 | 0 | } |
1386 | | |
1387 | | /* -------------------------------------------------------------------- */ |
1388 | | /* We need to calculate the maximum flow first */ |
1389 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&flow, 0); |
1390 | 0 | IGRAPH_CHECK(igraph_maxflow(graph, value, &flow, /*cut=*/ NULL, |
1391 | 0 | /*partition1=*/ NULL, /*partition2=*/ NULL, |
1392 | 0 | /*source=*/ source, /*target=*/ target, |
1393 | 0 | capacity, &stats)); |
1394 | | |
1395 | | /* -------------------------------------------------------------------- */ |
1396 | | /* Then we need the reverse residual graph */ |
1397 | 0 | IGRAPH_CHECK(igraph_reverse_residual_graph(graph, capacity, &residual, &flow)); |
1398 | 0 | IGRAPH_FINALLY(igraph_destroy, &residual); |
1399 | | |
1400 | | /* -------------------------------------------------------------------- */ |
1401 | | /* We shrink it to its strongly connected components */ |
1402 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&NtoL, 0); |
1403 | 0 | IGRAPH_CHECK(igraph_connected_components( |
1404 | 0 | &residual, /*membership=*/ &NtoL, /*csize=*/ NULL, |
1405 | 0 | /*no=*/ &proj_nodes, IGRAPH_STRONG |
1406 | 0 | )); |
1407 | 0 | IGRAPH_CHECK(igraph_contract_vertices(&residual, /*mapping=*/ &NtoL, /*vertex_comb=*/ NULL)); |
1408 | 0 | IGRAPH_CHECK(igraph_simplify(&residual, /*remove_multiple=*/ true, /*remove_loops=*/ true, /*edge_comb=*/ NULL)); |
1409 | | |
1410 | | /* We relabel the residual graph so that it is in topological sort order. */ |
1411 | 0 | igraph_int_t no_of_nodes_residual = igraph_vcount(&residual); |
1412 | 0 | igraph_vector_int_t order; |
1413 | 0 | igraph_t tmpgraph; |
1414 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes_residual); |
1415 | 0 | IGRAPH_CHECK(igraph_topological_sorting(&residual, &order, IGRAPH_OUT)); |
1416 | | |
1417 | | /* Invert order to get permutation to ensure vertices follow topological order. */ |
1418 | 0 | igraph_vector_int_t inv_order; |
1419 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&inv_order, no_of_nodes_residual); |
1420 | 0 | for (i = 0; i < no_of_nodes_residual; i++) { |
1421 | 0 | VECTOR(inv_order)[VECTOR(order)[i]] = i; |
1422 | 0 | } |
1423 | | |
1424 | | // Relabel mapping |
1425 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1426 | 0 | VECTOR(NtoL)[i] = VECTOR(inv_order)[VECTOR(NtoL)[i]]; |
1427 | 0 | } |
1428 | | |
1429 | | /* Permute vertices and replace residual with tmpgraph that is topologically |
1430 | | * sorted. |
1431 | | */ |
1432 | 0 | IGRAPH_CHECK(igraph_permute_vertices(&residual, &tmpgraph, &order)); |
1433 | | |
1434 | 0 | igraph_destroy(&residual); // We first free memory from original residual graph |
1435 | 0 | residual = tmpgraph; // Then we replace it by allocated memory from tmpgraph |
1436 | |
|
1437 | 0 | igraph_vector_int_destroy(&inv_order); |
1438 | 0 | igraph_vector_int_destroy(&order); |
1439 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1440 | |
|
1441 | 0 | newsource = VECTOR(NtoL)[source]; |
1442 | 0 | newtarget = VECTOR(NtoL)[target]; |
1443 | | |
1444 | | /* TODO: handle the newsource == newtarget case */ |
1445 | | |
1446 | | /* -------------------------------------------------------------------- */ |
1447 | | /* Determine the active vertices in the projection */ |
1448 | 0 | IGRAPH_BITSET_INIT_FINALLY(&VE1bool, proj_nodes); |
1449 | 0 | for (i = 0; i < no_of_edges; i++) { |
1450 | 0 | if (VECTOR(flow)[i] > 0) { |
1451 | 0 | igraph_int_t from = IGRAPH_FROM(graph, i); |
1452 | 0 | igraph_int_t to = IGRAPH_TO(graph, i); |
1453 | 0 | igraph_int_t pfrom = VECTOR(NtoL)[from]; |
1454 | 0 | igraph_int_t pto = VECTOR(NtoL)[to]; |
1455 | 0 | if (!IGRAPH_BIT_TEST(VE1bool, pfrom)) { |
1456 | 0 | IGRAPH_BIT_SET(VE1bool, pfrom); |
1457 | 0 | } |
1458 | 0 | if (!IGRAPH_BIT_TEST(VE1bool, pto)) { |
1459 | 0 | IGRAPH_BIT_SET(VE1bool, pto); |
1460 | 0 | } |
1461 | 0 | } |
1462 | 0 | } |
1463 | |
|
1464 | 0 | if (cuts) { |
1465 | 0 | igraph_vector_int_list_clear(cuts); |
1466 | 0 | } |
1467 | 0 | if (partition1s) { |
1468 | 0 | igraph_vector_int_list_clear(partition1s); |
1469 | 0 | } |
1470 | | |
1471 | | /* -------------------------------------------------------------------- */ |
1472 | | /* Everything is ready, list the cuts, using the right PIVOT |
1473 | | function */ |
1474 | 0 | IGRAPH_CHECK(igraph_marked_queue_int_init(&S, no_of_nodes)); |
1475 | 0 | IGRAPH_FINALLY(igraph_marked_queue_int_destroy, &S); |
1476 | 0 | IGRAPH_CHECK(igraph_estack_init(&T, no_of_nodes, 0)); |
1477 | 0 | IGRAPH_FINALLY(igraph_estack_destroy, &T); |
1478 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&cut, 0); |
1479 | | |
1480 | 0 | pivot_data.active = &VE1bool; |
1481 | |
|
1482 | 0 | IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&closedsets, 0); |
1483 | 0 | IGRAPH_CHECK(igraph_provan_shier_list(&residual, &S, &T, |
1484 | 0 | newsource, newtarget, &closedsets, |
1485 | 0 | igraph_i_all_st_mincuts_pivot, |
1486 | 0 | &pivot_data)); |
1487 | | |
1488 | | /* Convert the closed sets in the contracted graphs to cutsets in the |
1489 | | original graph */ |
1490 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&revmap_ptr, igraph_vcount(&residual)); |
1491 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&revmap_next, no_of_nodes); |
1492 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1493 | 0 | igraph_int_t id = VECTOR(NtoL)[i]; |
1494 | 0 | VECTOR(revmap_next)[i] = VECTOR(revmap_ptr)[id]; |
1495 | 0 | VECTOR(revmap_ptr)[id] = i + 1; |
1496 | 0 | } |
1497 | | |
1498 | | /* Create partitions in original graph */ |
1499 | 0 | nocuts = igraph_vector_int_list_size(&closedsets); |
1500 | 0 | igraph_vector_int_list_clear(mypartition1s); |
1501 | 0 | IGRAPH_CHECK(igraph_vector_int_list_reserve(mypartition1s, nocuts)); |
1502 | 0 | for (i = 0; i < nocuts; i++) { |
1503 | 0 | igraph_vector_int_t *supercut = igraph_vector_int_list_get_ptr(&closedsets, i); |
1504 | 0 | igraph_int_t j, supercutsize = igraph_vector_int_size(supercut); |
1505 | |
|
1506 | 0 | igraph_vector_int_clear(&cut); |
1507 | 0 | for (j = 0; j < supercutsize; j++) { |
1508 | 0 | igraph_int_t vtx = VECTOR(*supercut)[j]; |
1509 | 0 | igraph_int_t ovtx = VECTOR(revmap_ptr)[vtx]; |
1510 | 0 | while (ovtx != 0) { |
1511 | 0 | ovtx--; |
1512 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&cut, ovtx)); |
1513 | 0 | ovtx = VECTOR(revmap_next)[ovtx]; |
1514 | 0 | } |
1515 | 0 | } |
1516 | | |
1517 | 0 | IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(mypartition1s, &cut)); |
1518 | | |
1519 | | /* TODO: we could already reclaim the memory taken by 'supercut' here */ |
1520 | 0 | } |
1521 | | |
1522 | 0 | igraph_vector_int_destroy(&revmap_next); |
1523 | 0 | igraph_vector_int_destroy(&revmap_ptr); |
1524 | 0 | igraph_vector_int_list_destroy(&closedsets); |
1525 | 0 | IGRAPH_FINALLY_CLEAN(3); |
1526 | | |
1527 | | /* Create cuts in original graph */ |
1528 | 0 | if (cuts) { |
1529 | 0 | igraph_vector_int_t memb; |
1530 | |
|
1531 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&memb, no_of_nodes); |
1532 | 0 | IGRAPH_CHECK(igraph_vector_int_list_reserve(cuts, nocuts)); |
1533 | | |
1534 | 0 | for (i = 0; i < nocuts; i++) { |
1535 | 0 | igraph_vector_int_t *part = igraph_vector_int_list_get_ptr(mypartition1s, i); |
1536 | 0 | igraph_int_t j, n = igraph_vector_int_size(part); |
1537 | |
|
1538 | 0 | igraph_vector_int_clear(&cut); |
1539 | 0 | for (j = 0; j < n; j++) { |
1540 | 0 | igraph_int_t vtx = VECTOR(*part)[j]; |
1541 | 0 | VECTOR(memb)[vtx] = i + 1; |
1542 | 0 | } |
1543 | 0 | for (j = 0; j < no_of_edges; j++) { |
1544 | 0 | if (VECTOR(flow)[j] > 0) { |
1545 | 0 | igraph_int_t from = IGRAPH_FROM(graph, j); |
1546 | 0 | igraph_int_t to = IGRAPH_TO(graph, j); |
1547 | 0 | if (VECTOR(memb)[from] == i + 1 && VECTOR(memb)[to] != i + 1) { |
1548 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&cut, j)); |
1549 | 0 | } |
1550 | 0 | } |
1551 | 0 | } |
1552 | | |
1553 | 0 | IGRAPH_CHECK(igraph_vector_int_list_push_back_copy(cuts, &cut)); |
1554 | 0 | } |
1555 | | |
1556 | 0 | igraph_vector_int_destroy(&memb); |
1557 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1558 | 0 | } |
1559 | | |
1560 | 0 | igraph_vector_int_destroy(&cut); |
1561 | 0 | igraph_estack_destroy(&T); |
1562 | 0 | igraph_marked_queue_int_destroy(&S); |
1563 | 0 | igraph_bitset_destroy(&VE1bool); |
1564 | 0 | igraph_vector_int_destroy(&NtoL); |
1565 | 0 | igraph_destroy(&residual); |
1566 | 0 | igraph_vector_destroy(&flow); |
1567 | 0 | IGRAPH_FINALLY_CLEAN(7); |
1568 | |
|
1569 | 0 | if (!partition1s) { |
1570 | 0 | igraph_vector_int_list_destroy(mypartition1s); |
1571 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1572 | 0 | } |
1573 | |
|
1574 | 0 | return IGRAPH_SUCCESS; |
1575 | 0 | } |