/src/igraph/src/flow/flow.c
Line | Count | Source |
1 | | /* |
2 | | igraph library. |
3 | | Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com> |
4 | | 334 Harvard street, Cambridge, MA 02139 USA |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 2 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | | 02110-1301 USA |
20 | | |
21 | | */ |
22 | | |
23 | | #include "igraph_flow.h" |
24 | | |
25 | | #include "igraph_adjlist.h" |
26 | | #include "igraph_components.h" |
27 | | #include "igraph_conversion.h" |
28 | | #include "igraph_constants.h" |
29 | | #include "igraph_constructors.h" |
30 | | #include "igraph_cycles.h" |
31 | | #include "igraph_dqueue.h" |
32 | | #include "igraph_error.h" |
33 | | #include "igraph_interface.h" |
34 | | #include "igraph_progress.h" |
35 | | #include "igraph_operators.h" |
36 | | #include "igraph_structural.h" |
37 | | |
38 | | #include "core/buckets.h" |
39 | | #include "core/cutheap.h" |
40 | | #include "core/interruption.h" |
41 | | #include "flow/flow_internal.h" |
42 | | #include "math/safe_intop.h" |
43 | | |
44 | | /* |
45 | | * Some general remarks about the functions in this file. |
46 | | * |
47 | | * The following measures can be calculated: |
48 | | * ( 1) s-t maximum flow value, directed graph |
49 | | * ( 2) s-t maximum flow value, undirected graph |
50 | | * ( 3) s-t maximum flow, directed graph |
51 | | * ( 4) s-t maximum flow, undirected graph |
52 | | * ( 5) s-t minimum cut value, directed graph |
53 | | * ( 6) s-t minimum cut value, undirected graph |
54 | | * ( 7) minimum cut value, directed graph |
55 | | * ( 8) minimum cut value, undirected graph |
56 | | * ( 9) s-t minimum cut, directed graph |
57 | | * (10) s-t minimum cut, undirected graph |
58 | | * (11) minimum cut, directed graph |
59 | | * (12) minimum cut, undirected graph |
60 | | * (13) s-t edge connectivity, directed graph |
61 | | * (14) s-t edge connectivity, undirected graph |
62 | | * (15) edge connectivity, directed graph |
63 | | * (16) edge connectivity, undirected graph |
64 | | * (17) s-t vertex connectivity, directed graph |
65 | | * (18) s-t vertex connectivity, undirected graph |
66 | | * (19) vertex connectivity, directed graph |
67 | | * (20) vertex connectivity, undirected graph |
68 | | * (21) s-t number of edge disjoint paths, directed graph |
69 | | * (22) s-t number of edge disjoint paths, undirected graph |
70 | | * (23) s-t number of vertex disjoint paths, directed graph |
71 | | * (24) s-t number of vertex disjoint paths, undirected graph |
72 | | * (25) graph adhesion, directed graph |
73 | | * (26) graph adhesion, undirected graph |
74 | | * (27) graph cohesion, directed graph |
75 | | * (28) graph cohesion, undirected graph |
76 | | * |
77 | | * This is how they are calculated: |
78 | | * ( 1) igraph_maxflow_value, calls igraph_maxflow. |
79 | | * ( 2) igraph_maxflow_value, calls igraph_maxflow, this calls |
80 | | * igraph_i_maxflow_undirected. This transforms the graph into a |
81 | | * directed graph, including two mutual edges instead of every |
82 | | * undirected edge, then igraph_maxflow is called again with the |
83 | | * directed graph. |
84 | | * ( 3) igraph_maxflow, does the push-relabel algorithm, optionally |
85 | | * calculates the cut, the partitions and the flow itself. |
86 | | * ( 4) igraph_maxflow calls igraph_i_maxflow_undirected, this converts |
87 | | * the undirected graph into a directed one, adding two mutual edges |
88 | | * for each undirected edge, then igraph_maxflow is called again, |
89 | | * with the directed graph. After igraph_maxflow returns, we need |
90 | | * to edit the flow (and the cut) to make it sense for the |
91 | | * original graph. |
92 | | * ( 5) igraph_st_mincut_value, we just call igraph_maxflow_value |
93 | | * ( 6) igraph_st_mincut_value, we just call igraph_maxflow_value |
94 | | * ( 7) igraph_mincut_value, we call igraph_maxflow_value (|V|-1)*2 |
95 | | * times, from vertex 0 to all other vertices and from all other |
96 | | * vertices to vertex 0 |
97 | | * ( 8) We call igraph_i_mincut_value_undirected, that calls |
98 | | * igraph_i_mincut_undirected with partition=partition2=cut=NULL |
99 | | * The Stoer-Wagner algorithm is used. |
100 | | * ( 9) igraph_st_mincut, just calls igraph_maxflow. |
101 | | * (10) igraph_st_mincut, just calls igraph_maxflow. |
102 | | * (11) igraph_mincut, calls igraph_i_mincut_directed, which runs |
103 | | * the maximum flow algorithm 2(|V|-1) times, from vertex zero to |
104 | | * and from all other vertices and stores the smallest cut. |
105 | | * (12) igraph_mincut, igraph_i_mincut_undirected is called, |
106 | | * this is the Stoer-Wagner algorithm |
107 | | * (13) We just call igraph_maxflow_value, back to (1) |
108 | | * (14) We just call igraph_maxflow_value, back to (2) |
109 | | * (15) We just call igraph_mincut_value (possibly after some basic |
110 | | * checks). Back to (7) |
111 | | * (16) We just call igraph_mincut_value (possibly after some basic |
112 | | * checks). Back to (8). |
113 | | * (17) We call igraph_i_st_vertex_connectivity_directed. |
114 | | * That creates a new graph with 2*|V| vertices and smartly chosen |
115 | | * edges, so that the s-t edge connectivity of this graph is the |
116 | | * same as the s-t vertex connectivity of the original graph. |
117 | | * So finally it calls igraph_maxflow_value, go to (1) |
118 | | * (18) We call igraph_i_st_vertex_connectivity_undirected. |
119 | | * We convert the graph to a directed one, |
120 | | * IGRAPH_TO_DIRECTED_MUTUAL method. Then we call |
121 | | * igraph_i_st_vertex_connectivity_directed, see (17). |
122 | | * (19) We call igraph_i_vertex_connectivity_directed. |
123 | | * That calls igraph_st_vertex_connectivity for all pairs of |
124 | | * vertices. Back to (17). |
125 | | * (20) We call igraph_i_vertex_connectivity_undirected. |
126 | | * That converts the graph into a directed one |
127 | | * (IGRAPH_TO_DIRECTED_MUTUAL) and calls the directed version, |
128 | | * igraph_i_vertex_connectivity_directed, see (19). |
129 | | * (21) igraph_edge_disjoint_paths, we just call igraph_maxflow_value, (1). |
130 | | * (22) igraph_edge_disjoint_paths, we just call igraph_maxflow_value, (2). |
131 | | * (23) igraph_vertex_disjoint_paths, if there is a connection between |
132 | | * the two vertices, then we remove that (or all of them if there |
133 | | * are many), as this could mess up vertex connectivity |
134 | | * calculation. The we call |
135 | | * igraph_i_st_vertex_connectivity_directed, see (19). |
136 | | * (24) igraph_vertex_disjoint_paths, if there is a connection between |
137 | | * the two vertices, then we remove that (or all of them if there |
138 | | * are many), as this could mess up vertex connectivity |
139 | | * calculation. The we call |
140 | | * igraph_i_st_vertex_connectivity_undirected, see (20). |
141 | | * (25) We just call igraph_edge_connectivity, see (15). |
142 | | * (26) We just call igraph_edge_connectivity, see (16). |
143 | | * (27) We just call igraph_vertex_connectivity, see (19). |
144 | | * (28) We just call igraph_vertex_connectivity, see (20). |
145 | | */ |
146 | | |
147 | | /* |
148 | | * This is an internal function that calculates the maximum flow value |
149 | | * on undirected graphs, either for an s-t vertex pair or for the |
150 | | * graph (i.e. all vertex pairs). |
151 | | * |
152 | | * It does it by converting the undirected graph to a corresponding |
153 | | * directed graph, including reciprocal directed edges instead of each |
154 | | * undirected edge. |
155 | | */ |
156 | | |
157 | | static igraph_error_t igraph_i_maxflow_undirected( |
158 | | const igraph_t *graph, |
159 | | igraph_real_t *value, |
160 | | igraph_vector_t *flow, |
161 | | igraph_vector_int_t *cut, |
162 | | igraph_vector_int_t *partition, |
163 | | igraph_vector_int_t *partition2, |
164 | | igraph_int_t source, |
165 | | igraph_int_t target, |
166 | | const igraph_vector_t *capacity, |
167 | 0 | igraph_maxflow_stats_t *stats) { |
168 | |
|
169 | 0 | const igraph_int_t no_of_edges = igraph_ecount(graph); |
170 | 0 | const igraph_int_t no_of_nodes = igraph_vcount(graph); |
171 | 0 | igraph_vector_int_t edges; |
172 | 0 | igraph_vector_t newcapacity; |
173 | 0 | igraph_t newgraph; |
174 | 0 | igraph_int_t size; |
175 | | |
176 | | /* We need to convert this to directed by hand, since we need to be |
177 | | sure that the edge IDs will be handled properly to build the new |
178 | | capacity vector. */ |
179 | |
|
180 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); |
181 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&newcapacity, no_of_edges * 2); |
182 | 0 | IGRAPH_SAFE_MULT(no_of_edges, 4, &size); |
183 | 0 | IGRAPH_CHECK(igraph_vector_int_reserve(&edges, size)); |
184 | 0 | IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); |
185 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(&edges, size)); |
186 | 0 | for (igraph_int_t i = 0; i < no_of_edges; i++) { |
187 | 0 | VECTOR(edges)[no_of_edges * 2 + i * 2] = VECTOR(edges)[i * 2 + 1]; |
188 | 0 | VECTOR(edges)[no_of_edges * 2 + i * 2 + 1] = VECTOR(edges)[i * 2]; |
189 | 0 | VECTOR(newcapacity)[i] = VECTOR(newcapacity)[no_of_edges + i] = |
190 | 0 | capacity ? VECTOR(*capacity)[i] : 1.0; |
191 | 0 | } |
192 | |
|
193 | 0 | IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); |
194 | 0 | IGRAPH_FINALLY(igraph_destroy, &newgraph); |
195 | |
|
196 | 0 | IGRAPH_CHECK(igraph_maxflow(&newgraph, value, flow, cut, partition, |
197 | 0 | partition2, source, target, &newcapacity, stats)); |
198 | | |
199 | 0 | if (cut) { |
200 | 0 | igraph_int_t cs = igraph_vector_int_size(cut); |
201 | 0 | for (igraph_int_t i = 0; i < cs; i++) { |
202 | 0 | if (VECTOR(*cut)[i] >= no_of_edges) { |
203 | 0 | VECTOR(*cut)[i] -= no_of_edges; |
204 | 0 | } |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | /* The flow has one non-zero value for each real-nonreal edge pair, |
209 | | by definition, we convert it to a positive-negative vector. If |
210 | | for an edge the flow is negative that means that it is going |
211 | | from the bigger vertex ID to the smaller one. For positive |
212 | | values the direction is the opposite. */ |
213 | 0 | if (flow) { |
214 | 0 | for (igraph_int_t i = 0; i < no_of_edges; i++) { |
215 | 0 | VECTOR(*flow)[i] -= VECTOR(*flow)[i + no_of_edges]; |
216 | 0 | } |
217 | 0 | IGRAPH_CHECK(igraph_vector_resize(flow, no_of_edges)); |
218 | 0 | } |
219 | | |
220 | 0 | igraph_destroy(&newgraph); |
221 | 0 | igraph_vector_int_destroy(&edges); |
222 | 0 | igraph_vector_destroy(&newcapacity); |
223 | 0 | IGRAPH_FINALLY_CLEAN(3); |
224 | |
|
225 | 0 | return IGRAPH_SUCCESS; |
226 | 0 | } |
227 | | |
228 | 31.2M | #define FIRST(i) (VECTOR(*first)[(i)]) |
229 | 35.3M | #define LAST(i) (VECTOR(*first)[(i)+1]) |
230 | 45.8M | #define CURRENT(i) (VECTOR(*current)[(i)]) |
231 | 3.33G | #define RESCAP(i) (VECTOR(*rescap)[(i)]) |
232 | | #define REV(i) (VECTOR(*rev)[(i)]) |
233 | 1.08G | #define HEAD(i) (VECTOR(*to)[(i)]) |
234 | 181M | #define EXCESS(i) (VECTOR(*excess)[(i)]) |
235 | 2.32G | #define DIST(i) (VECTOR(*distance)[(i)]) |
236 | 11.0M | #define DISCHARGE(v) (igraph_i_mf_discharge((v), ¤t, &first, &rescap, \ |
237 | 11.0M | &to, &distance, &excess, \ |
238 | 11.0M | no_of_nodes, source, target, \ |
239 | 11.0M | &buckets, &ibuckets, \ |
240 | 11.0M | &rev, stats, &npushsince, \ |
241 | 11.0M | &nrelabelsince)) |
242 | 31.6M | #define PUSH(v,e,n) (igraph_i_mf_push((v), (e), (n), current, rescap, \ |
243 | 31.6M | excess, target, source, buckets, \ |
244 | 31.6M | ibuckets, distance, rev, stats, \ |
245 | 31.6M | npushsince)) |
246 | 5.94M | #define RELABEL(v) (igraph_i_mf_relabel((v), no_of_nodes, distance, \ |
247 | 5.94M | first, rescap, to, current, \ |
248 | 5.94M | stats, nrelabelsince)) |
249 | 195k | #define GAP(b) (igraph_i_mf_gap((b), stats, buckets, ibuckets, \ |
250 | 195k | no_of_nodes, distance)) |
251 | 18.0k | #define BFS() (igraph_i_mf_bfs(&bfsq, source, target, no_of_nodes, \ |
252 | 18.0k | &buckets, &ibuckets, &distance, \ |
253 | 18.0k | &first, ¤t, &to, &excess, \ |
254 | 18.0k | &rescap, &rev)) |
255 | | |
256 | | static void igraph_i_mf_gap(igraph_int_t b, igraph_maxflow_stats_t *stats, |
257 | | igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, |
258 | | igraph_int_t no_of_nodes, |
259 | 195k | igraph_vector_int_t *distance) { |
260 | | |
261 | 195k | IGRAPH_UNUSED(buckets); |
262 | | |
263 | 195k | igraph_int_t bo; |
264 | 195k | (stats->nogap)++; |
265 | 40.5M | for (bo = b + 1; bo <= no_of_nodes; bo++) { |
266 | 43.8M | while (!igraph_dbuckets_empty_bucket(ibuckets, bo)) { |
267 | 3.49M | igraph_int_t n = igraph_dbuckets_pop(ibuckets, bo); |
268 | 3.49M | (stats->nogapnodes)++; |
269 | 3.49M | DIST(n) = no_of_nodes; |
270 | 3.49M | } |
271 | 40.3M | } |
272 | 195k | } |
273 | | |
274 | | static void igraph_i_mf_relabel(igraph_int_t v, igraph_int_t no_of_nodes, |
275 | | igraph_vector_int_t *distance, |
276 | | igraph_vector_int_t *first, |
277 | | igraph_vector_t *rescap, igraph_vector_int_t *to, |
278 | | igraph_vector_int_t *current, |
279 | 5.94M | igraph_maxflow_stats_t *stats, igraph_int_t *nrelabelsince) { |
280 | | |
281 | 5.94M | igraph_int_t min = no_of_nodes; |
282 | 5.94M | igraph_int_t k, l, min_edge = 0; |
283 | 5.94M | (stats->norelabel)++; (*nrelabelsince)++; |
284 | 5.94M | DIST(v) = no_of_nodes; |
285 | 1.09G | for (k = FIRST(v), l = LAST(v); k < l; k++) { |
286 | 1.09G | if (RESCAP(k) > 0 && DIST(HEAD(k)) < min) { |
287 | 8.07M | min = DIST(HEAD(k)); |
288 | 8.07M | min_edge = k; |
289 | 8.07M | } |
290 | 1.09G | } |
291 | 5.94M | min++; |
292 | 5.94M | if (min < no_of_nodes) { |
293 | 5.66M | DIST(v) = min; |
294 | 5.66M | CURRENT(v) = min_edge; |
295 | 5.66M | } |
296 | 5.94M | } |
297 | | |
298 | | static void igraph_i_mf_push(igraph_int_t v, igraph_int_t e, igraph_int_t n, |
299 | | igraph_vector_int_t *current, |
300 | | igraph_vector_t *rescap, igraph_vector_t *excess, |
301 | | igraph_int_t target, igraph_int_t source, |
302 | | igraph_buckets_t *buckets, igraph_dbuckets_t *ibuckets, |
303 | | igraph_vector_int_t *distance, |
304 | | igraph_vector_int_t *rev, igraph_maxflow_stats_t *stats, |
305 | 31.6M | igraph_int_t *npushsince) { |
306 | | |
307 | 31.6M | IGRAPH_UNUSED(current); |
308 | 31.6M | IGRAPH_UNUSED(source); |
309 | | |
310 | 31.6M | igraph_real_t delta = |
311 | 31.6M | RESCAP(e) < EXCESS(v) ? RESCAP(e) : EXCESS(v); |
312 | 31.6M | (stats->nopush)++; (*npushsince)++; |
313 | 31.6M | if (EXCESS(n) == 0 && n != target) { |
314 | 9.85M | igraph_dbuckets_delete(ibuckets, DIST(n), n); |
315 | 9.85M | igraph_buckets_add(buckets, DIST(n), n); |
316 | 9.85M | } |
317 | 31.6M | RESCAP(e) -= delta; |
318 | 31.6M | RESCAP(REV(e)) += delta; |
319 | 31.6M | EXCESS(n) += delta; |
320 | 31.6M | EXCESS(v) -= delta; |
321 | 31.6M | } |
322 | | |
323 | | static void igraph_i_mf_discharge(igraph_int_t v, |
324 | | igraph_vector_int_t *current, |
325 | | igraph_vector_int_t *first, |
326 | | igraph_vector_t *rescap, |
327 | | igraph_vector_int_t *to, |
328 | | igraph_vector_int_t *distance, |
329 | | igraph_vector_t *excess, |
330 | | igraph_int_t no_of_nodes, igraph_int_t source, |
331 | | igraph_int_t target, igraph_buckets_t *buckets, |
332 | | igraph_dbuckets_t *ibuckets, |
333 | | igraph_vector_int_t *rev, |
334 | | igraph_maxflow_stats_t *stats, |
335 | 11.0M | igraph_int_t *npushsince, igraph_int_t *nrelabelsince) { |
336 | | |
337 | 16.7M | do { |
338 | 16.7M | igraph_int_t i; |
339 | 16.7M | igraph_int_t start = CURRENT(v); |
340 | 16.7M | igraph_int_t stop = LAST(v); |
341 | 1.09G | for (i = start; i < stop; i++) { |
342 | 1.09G | if (RESCAP(i) > 0) { |
343 | 576M | igraph_int_t nei = HEAD(i); |
344 | 576M | if (DIST(v) == DIST(nei) + 1) { |
345 | 31.6M | PUSH((v), i, nei); |
346 | 31.6M | if (EXCESS(v) == 0) { |
347 | 10.8M | break; |
348 | 10.8M | } |
349 | 31.6M | } |
350 | 576M | } |
351 | 1.09G | } |
352 | 16.7M | if (i == stop) { |
353 | 5.94M | igraph_int_t origdist = DIST(v); |
354 | 5.94M | RELABEL(v); |
355 | 5.94M | if (igraph_buckets_empty_bucket(buckets, origdist) && |
356 | 3.71M | igraph_dbuckets_empty_bucket(ibuckets, origdist)) { |
357 | 195k | GAP(origdist); |
358 | 195k | } |
359 | 5.94M | if (DIST(v) == no_of_nodes) { |
360 | 277k | break; |
361 | 277k | } |
362 | 10.8M | } else { |
363 | 10.8M | CURRENT(v) = i; |
364 | 10.8M | igraph_dbuckets_add(ibuckets, DIST(v), v); |
365 | 10.8M | break; |
366 | 10.8M | } |
367 | 16.7M | } while (1); |
368 | 11.0M | } |
369 | | |
370 | | static igraph_error_t igraph_i_mf_bfs(igraph_dqueue_int_t *bfsq, |
371 | | igraph_int_t source, igraph_int_t target, |
372 | | igraph_int_t no_of_nodes, igraph_buckets_t *buckets, |
373 | | igraph_dbuckets_t *ibuckets, |
374 | | igraph_vector_int_t *distance, |
375 | | igraph_vector_int_t *first, igraph_vector_int_t *current, |
376 | | igraph_vector_int_t *to, igraph_vector_t *excess, |
377 | 69.9k | igraph_vector_t *rescap, igraph_vector_int_t *rev) { |
378 | | |
379 | 69.9k | igraph_int_t k, l; |
380 | | |
381 | 69.9k | IGRAPH_UNUSED(source); |
382 | | |
383 | 69.9k | igraph_buckets_clear(buckets); |
384 | 69.9k | igraph_dbuckets_clear(ibuckets); |
385 | 69.9k | igraph_vector_int_fill(distance, no_of_nodes); |
386 | 69.9k | DIST(target) = 0; |
387 | | |
388 | 69.9k | IGRAPH_CHECK(igraph_dqueue_int_push(bfsq, target)); |
389 | 12.7M | while (!igraph_dqueue_int_empty(bfsq)) { |
390 | 12.6M | igraph_int_t node = igraph_dqueue_int_pop(bfsq); |
391 | 12.6M | igraph_int_t ndist = DIST(node) + 1; |
392 | 1.04G | for (k = FIRST(node), l = LAST(node); k < l; k++) { |
393 | 1.03G | if (RESCAP(REV(k)) > 0) { |
394 | 509M | igraph_int_t nei = HEAD(k); |
395 | 509M | if (DIST(nei) == no_of_nodes) { |
396 | 12.6M | DIST(nei) = ndist; |
397 | 12.6M | CURRENT(nei) = FIRST(nei); |
398 | 12.6M | if (EXCESS(nei) > 0) { |
399 | 1.53M | igraph_buckets_add(buckets, ndist, nei); |
400 | 11.0M | } else { |
401 | 11.0M | igraph_dbuckets_add(ibuckets, ndist, nei); |
402 | 11.0M | } |
403 | 12.6M | IGRAPH_CHECK(igraph_dqueue_int_push(bfsq, nei)); |
404 | 12.6M | } |
405 | 509M | } |
406 | 1.03G | } |
407 | 12.6M | } |
408 | | |
409 | 69.9k | return IGRAPH_SUCCESS; |
410 | 69.9k | } |
411 | | |
412 | | /** |
413 | | * \function igraph_maxflow |
414 | | * \brief Maximum network flow between a pair of vertices. |
415 | | * |
416 | | * This function implements the Goldberg-Tarjan algorithm for |
417 | | * calculating value of the maximum flow in a directed or undirected |
418 | | * graph. The algorithm was given in Andrew V. Goldberg, Robert |
419 | | * E. Tarjan: A New Approach to the Maximum-Flow Problem, Journal of |
420 | | * the ACM, 35(4), 921-940, 1988 |
421 | | * https://doi.org/10.1145/48014.61051. |
422 | | * |
423 | | * </para><para> |
424 | | * The input of the function is a graph, a vector |
425 | | * of real numbers giving the capacity of the edges and two vertices |
426 | | * of the graph, the source and the target. A flow is a function |
427 | | * assigning positive real numbers to the edges and satisfying two |
428 | | * requirements: (1) the flow value is less than the capacity of the |
429 | | * edge and (2) at each vertex except the source and the target, the |
430 | | * incoming flow (i.e. the sum of the flow on the incoming edges) is |
431 | | * the same as the outgoing flow (i.e. the sum of the flow on the |
432 | | * outgoing edges). The value of the flow is the incoming flow at the |
433 | | * target vertex. The maximum flow is the flow with the maximum |
434 | | * value. |
435 | | * |
436 | | * \param graph The input graph, either directed or undirected. |
437 | | * \param value Pointer to a real number, the value of the maximum |
438 | | * will be placed here, unless it is a null pointer. |
439 | | * \param flow If not a null pointer, then it must be a pointer to an |
440 | | * initialized vector. The vector will be resized, and the flow |
441 | | * on each edge will be placed in it, in the order of the edge |
442 | | * IDs. For undirected graphs this argument is bit trickier, |
443 | | * since for these the flow direction is not predetermined by |
444 | | * the edge direction. For these graphs the elements of the |
445 | | * \p flow vector can be negative, this means that the flow |
446 | | * goes from the bigger vertex ID to the smaller one. Positive |
447 | | * values mean that the flow goes from the smaller vertex ID to |
448 | | * the bigger one. |
449 | | * \param cut A null pointer or a pointer to an initialized vector. |
450 | | * If not a null pointer, then the minimum cut corresponding to |
451 | | * the maximum flow is stored here, i.e. all edge IDs that are |
452 | | * part of the minimum cut are stored in the vector. |
453 | | * \param partition A null pointer or a pointer to an initialized |
454 | | * vector. If not a null pointer, then the first partition of |
455 | | * the minimum cut that corresponds to the maximum flow will be |
456 | | * placed here. The first partition is always the one that |
457 | | * contains the source vertex. |
458 | | * \param partition2 A null pointer or a pointer to an initialized |
459 | | * vector. If not a null pointer, then the second partition of |
460 | | * the minimum cut that corresponds to the maximum flow will be |
461 | | * placed here. The second partition is always the one that |
462 | | * contains the target vertex. |
463 | | * \param source The id of the source vertex. |
464 | | * \param target The id of the target vertex. |
465 | | * \param capacity Vector containing the capacity of the edges. If \c NULL, then |
466 | | * every edge is considered to have capacity 1.0. |
467 | | * \param stats Counts of the number of different operations |
468 | | * performed by the algorithm are stored here. |
469 | | * \return Error code. |
470 | | * |
471 | | * Time complexity: O(|V|^3). In practice it is much faster, but I |
472 | | * cannot prove a better lower bound for the data structure I've |
473 | | * used. In fact, this implementation runs much faster than the |
474 | | * \c hi_pr implementation discussed in |
475 | | * B. V. Cherkassky and A. V. Goldberg: On implementing the |
476 | | * push-relabel method for the maximum flow problem, (Algorithmica, |
477 | | * 19:390--410, 1997) on all the graph classes I've tried. |
478 | | * |
479 | | * \sa \ref igraph_mincut_value(), \ref igraph_edge_connectivity(), |
480 | | * \ref igraph_vertex_connectivity() for |
481 | | * properties based on the maximum flow. |
482 | | * |
483 | | * \example examples/simple/flow.c |
484 | | * \example examples/simple/flow2.c |
485 | | */ |
486 | | |
487 | | igraph_error_t igraph_maxflow(const igraph_t *graph, igraph_real_t *value, |
488 | | igraph_vector_t *flow, igraph_vector_int_t *cut, |
489 | | igraph_vector_int_t *partition, igraph_vector_int_t *partition2, |
490 | | igraph_int_t source, igraph_int_t target, |
491 | | const igraph_vector_t *capacity, |
492 | 51.8k | igraph_maxflow_stats_t *stats) { |
493 | | |
494 | 51.8k | const igraph_int_t no_of_nodes = igraph_vcount(graph); |
495 | 51.8k | const igraph_int_t no_of_orig_edges = igraph_ecount(graph); |
496 | 51.8k | const igraph_int_t no_of_edges = 2 * no_of_orig_edges; |
497 | | |
498 | 51.8k | igraph_vector_t rescap, excess; |
499 | 51.8k | igraph_vector_int_t from, to, rev, distance; |
500 | 51.8k | igraph_vector_int_t edges, rank; |
501 | 51.8k | igraph_vector_int_t current, first; |
502 | 51.8k | igraph_buckets_t buckets; |
503 | 51.8k | igraph_dbuckets_t ibuckets; |
504 | | |
505 | 51.8k | igraph_dqueue_int_t bfsq; |
506 | | |
507 | 51.8k | igraph_int_t idx; |
508 | 51.8k | igraph_int_t npushsince = 0, nrelabelsince = 0; |
509 | | |
510 | 51.8k | igraph_maxflow_stats_t local_stats; /* used if the user passed a null pointer for stats */ |
511 | | |
512 | 51.8k | if (stats == NULL) { |
513 | 51.8k | stats = &local_stats; |
514 | 51.8k | } |
515 | | |
516 | 51.8k | if (!igraph_is_directed(graph)) { |
517 | 0 | IGRAPH_CHECK(igraph_i_maxflow_undirected(graph, value, flow, cut, |
518 | 0 | partition, partition2, source, |
519 | 0 | target, capacity, stats)); |
520 | 0 | return IGRAPH_SUCCESS; |
521 | 0 | } |
522 | | |
523 | 51.8k | if (capacity && igraph_vector_size(capacity) != no_of_orig_edges) { |
524 | 0 | IGRAPH_ERROR("Capacity vector must match number of edges in length.", IGRAPH_EINVAL); |
525 | 0 | } |
526 | 51.8k | if (source < 0 || source >= no_of_nodes || target < 0 || target >= no_of_nodes) { |
527 | 0 | IGRAPH_ERROR("Invalid source or target vertex.", IGRAPH_EINVVID); |
528 | 0 | } |
529 | 51.8k | if (source == target) { |
530 | 0 | IGRAPH_ERROR("Source and target vertices are the same.", IGRAPH_EINVAL); |
531 | 0 | } |
532 | | |
533 | 51.8k | stats->nopush = stats->norelabel = stats->nogap = stats->nogapnodes = |
534 | 51.8k | stats->nobfs = 0; |
535 | | |
536 | | /* |
537 | | * The data structure: |
538 | | * - First of all, we consider every edge twice, first the edge |
539 | | * itself, but also its opposite. |
540 | | * - (from, to) contain all edges (original + opposite), ordered by |
541 | | * the id of the source vertex. During the algorithm we just need |
542 | | * 'to', so from is destroyed soon. We only need it in the |
543 | | * beginning, to create the 'first' pointers. |
544 | | * - 'first' is a pointer vector for 'to', first[i] points to the |
545 | | * first neighbor of vertex i and first[i+1]-1 is the last |
546 | | * neighbor of vertex i. (Unless vertex i is isolate, in which |
547 | | * case first[i]==first[i+1]). |
548 | | * - 'rev' contains a mapping from an edge to its opposite pair |
549 | | * - 'rescap' contains the residual capacities of the edges, this is |
550 | | * initially equal to the capacity of the edges for the original |
551 | | * edges and it is zero for the opposite edges. |
552 | | * - 'excess' contains the excess flow for the vertices. I.e. the flow |
553 | | * that is coming in, but it is not going out. |
554 | | * - 'current' stores the next neighboring vertex to check, for every |
555 | | * vertex, when excess flow is being pushed to neighbors. |
556 | | * - 'distance' stores the distance of the vertices from the source. |
557 | | * - 'rank' and 'edges' are only needed temporarily, for ordering and |
558 | | * storing the edges. |
559 | | * - we use an igraph_buckets_t data structure ('buckets') to find |
560 | | * the vertices with the highest 'distance' values quickly. |
561 | | * This always contains the vertices that have a positive excess |
562 | | * flow. |
563 | | */ |
564 | 51.8k | #undef FIRST |
565 | 51.8k | #undef LAST |
566 | 51.8k | #undef CURRENT |
567 | 51.8k | #undef RESCAP |
568 | 51.8k | #undef REV |
569 | 51.8k | #undef HEAD |
570 | 51.8k | #undef EXCESS |
571 | 51.8k | #undef DIST |
572 | 51.8k | #define FIRST(i) (VECTOR(first)[(i)]) |
573 | 51.8k | #define LAST(i) (VECTOR(first)[(i)+1]) |
574 | 51.8k | #define CURRENT(i) (VECTOR(current)[(i)]) |
575 | 26.5M | #define RESCAP(i) (VECTOR(rescap)[(i)]) |
576 | 51.8k | #define REV(i) (VECTOR(rev)[(i)]) |
577 | 30.9M | #define HEAD(i) (VECTOR(to)[(i)]) |
578 | 8.91M | #define EXCESS(i) (VECTOR(excess)[(i)]) |
579 | 51.8k | #define DIST(i) (VECTOR(distance)[(i)]) |
580 | | |
581 | 51.8k | IGRAPH_CHECK(igraph_dqueue_int_init(&bfsq, no_of_nodes)); |
582 | 51.8k | IGRAPH_FINALLY(igraph_dqueue_int_destroy, &bfsq); |
583 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&to, no_of_edges); |
584 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&rev, no_of_edges); |
585 | 51.8k | IGRAPH_VECTOR_INIT_FINALLY(&rescap, no_of_edges); |
586 | 51.8k | IGRAPH_VECTOR_INIT_FINALLY(&excess, no_of_nodes); |
587 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&distance, no_of_nodes); |
588 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&first, no_of_nodes + 1); |
589 | | |
590 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&rank, no_of_edges); |
591 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&from, no_of_edges); |
592 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges); |
593 | | |
594 | | /* Create the basic data structure */ |
595 | 51.8k | IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); |
596 | 51.8k | IGRAPH_CHECK(igraph_i_vector_int_rank(&edges, &rank, no_of_nodes)); |
597 | | |
598 | 429M | for (igraph_int_t i = 0; i < no_of_edges; i += 2) { |
599 | 429M | const igraph_int_t pos = VECTOR(rank)[i]; |
600 | 429M | const igraph_int_t pos2 = VECTOR(rank)[i + 1]; |
601 | 429M | VECTOR(from)[pos] = VECTOR(edges)[i]; |
602 | 429M | VECTOR(to)[pos] = VECTOR(edges)[i + 1]; |
603 | 429M | VECTOR(from)[pos2] = VECTOR(edges)[i + 1]; |
604 | 429M | VECTOR(to)[pos2] = VECTOR(edges)[i]; |
605 | 429M | VECTOR(rev)[pos] = pos2; |
606 | 429M | VECTOR(rev)[pos2] = pos; |
607 | 429M | VECTOR(rescap)[pos] = capacity ? VECTOR(*capacity)[i / 2] : 1.0; |
608 | 429M | VECTOR(rescap)[pos2] = 0.0; |
609 | 429M | } |
610 | | |
611 | | /* The first pointers. This is a but trickier, than one would |
612 | | think, because of the possible isolate vertices. */ |
613 | | |
614 | 51.8k | idx = -1; |
615 | 103k | for (igraph_int_t i = 0; i <= VECTOR(from)[0]; i++) { |
616 | 51.8k | idx++; VECTOR(first)[idx] = 0; |
617 | 51.8k | } |
618 | 858M | for (igraph_int_t i = 1; i < no_of_edges; i++) { |
619 | 858M | const igraph_int_t n = (VECTOR(from)[i] - |
620 | 858M | VECTOR(from)[ VECTOR(first)[idx] ]); |
621 | 869M | for (igraph_int_t j = 0; j < n; j++) { |
622 | 10.7M | idx++; VECTOR(first)[idx] = i; |
623 | 10.7M | } |
624 | 858M | } |
625 | 51.8k | idx++; |
626 | 103k | while (idx < no_of_nodes + 1) { |
627 | 51.8k | VECTOR(first)[idx++] = no_of_edges; |
628 | 51.8k | } |
629 | | |
630 | 51.8k | igraph_vector_int_destroy(&from); |
631 | 51.8k | igraph_vector_int_destroy(&edges); |
632 | 51.8k | IGRAPH_FINALLY_CLEAN(2); |
633 | | |
634 | 51.8k | if (!flow) { |
635 | 51.8k | igraph_vector_int_destroy(&rank); |
636 | 51.8k | IGRAPH_FINALLY_CLEAN(1); |
637 | 51.8k | } |
638 | | |
639 | | /* And the current pointers, initially the same as the first */ |
640 | 51.8k | IGRAPH_VECTOR_INT_INIT_FINALLY(¤t, no_of_nodes); |
641 | 10.8M | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
642 | 10.8M | VECTOR(current)[i] = VECTOR(first)[i]; |
643 | 10.8M | } |
644 | | |
645 | | /* OK, the graph is set up, initialization */ |
646 | | |
647 | 51.8k | IGRAPH_CHECK(igraph_buckets_init(&buckets, no_of_nodes + 1, no_of_nodes)); |
648 | 51.8k | IGRAPH_FINALLY(igraph_buckets_destroy, &buckets); |
649 | 51.8k | IGRAPH_CHECK(igraph_dbuckets_init(&ibuckets, no_of_nodes + 1, no_of_nodes)); |
650 | 51.8k | IGRAPH_FINALLY(igraph_dbuckets_destroy, &ibuckets); |
651 | | |
652 | | /* Send as much flow as possible from the source to its neighbors */ |
653 | 31.0M | for (igraph_int_t i = FIRST(source), j = LAST(source); i < j; i++) { |
654 | 30.9M | if (HEAD(i) != source) { |
655 | 8.85M | const igraph_real_t delta = RESCAP(i); |
656 | 8.85M | RESCAP(i) = 0; |
657 | 8.85M | RESCAP(REV(i)) += delta; |
658 | 8.85M | EXCESS(HEAD(i)) += delta; |
659 | 8.85M | } |
660 | 30.9M | } |
661 | | |
662 | 51.8k | IGRAPH_CHECK(BFS()); |
663 | 51.8k | (stats->nobfs)++; |
664 | | |
665 | 11.1M | while (!igraph_buckets_empty(&buckets)) { |
666 | 11.0M | const igraph_int_t vertex = igraph_buckets_popmax(&buckets); |
667 | 11.0M | DISCHARGE(vertex); |
668 | 11.0M | if (npushsince > no_of_nodes / 2 && nrelabelsince > no_of_nodes) { |
669 | 18.0k | (stats->nobfs)++; |
670 | 18.0k | BFS(); |
671 | 18.0k | npushsince = nrelabelsince = 0; |
672 | 18.0k | } |
673 | 11.0M | } |
674 | | |
675 | | /* Store the result */ |
676 | 51.8k | if (value) { |
677 | 51.8k | *value = EXCESS(target); |
678 | 51.8k | } |
679 | | |
680 | | /* If we also need the minimum cut */ |
681 | 51.8k | if (cut || partition || partition2) { |
682 | | /* We need to find all vertices from which the target is reachable |
683 | | in the residual graph. We do a breadth-first search, going |
684 | | backwards. */ |
685 | 0 | igraph_dqueue_int_t Q; |
686 | 0 | igraph_vector_bool_t added; |
687 | 0 | igraph_int_t marked = 0; |
688 | |
|
689 | 0 | IGRAPH_CHECK(igraph_vector_bool_init(&added, no_of_nodes)); |
690 | 0 | IGRAPH_FINALLY(igraph_vector_bool_destroy, &added); |
691 | |
|
692 | 0 | IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100)); |
693 | 0 | IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q); |
694 | |
|
695 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, target)); |
696 | 0 | VECTOR(added)[target] = true; |
697 | 0 | marked++; |
698 | 0 | while (!igraph_dqueue_int_empty(&Q)) { |
699 | 0 | const igraph_int_t actnode = igraph_dqueue_int_pop(&Q); |
700 | 0 | for (igraph_int_t i = FIRST(actnode), j = LAST(actnode); i < j; i++) { |
701 | 0 | igraph_int_t nei = HEAD(i); |
702 | 0 | if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) { |
703 | 0 | VECTOR(added)[nei] = true; |
704 | 0 | marked++; |
705 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei)); |
706 | 0 | } |
707 | 0 | } |
708 | 0 | } |
709 | 0 | igraph_dqueue_int_destroy(&Q); |
710 | 0 | IGRAPH_FINALLY_CLEAN(1); |
711 | | |
712 | | /* Now we marked each vertex that is on one side of the cut, |
713 | | check the crossing edges */ |
714 | |
|
715 | 0 | if (cut) { |
716 | 0 | igraph_vector_int_clear(cut); |
717 | 0 | for (igraph_int_t i = 0; i < no_of_orig_edges; i++) { |
718 | 0 | igraph_int_t f = IGRAPH_FROM(graph, i); |
719 | 0 | igraph_int_t t = IGRAPH_TO(graph, i); |
720 | 0 | if (!VECTOR(added)[f] && VECTOR(added)[t]) { |
721 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(cut, i)); |
722 | 0 | } |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | 0 | if (partition2) { |
727 | 0 | igraph_int_t x = 0; |
728 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition2, marked)); |
729 | 0 | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
730 | 0 | if (VECTOR(added)[i]) { |
731 | 0 | VECTOR(*partition2)[x++] = i; |
732 | 0 | } |
733 | 0 | } |
734 | 0 | } |
735 | | |
736 | 0 | if (partition) { |
737 | 0 | igraph_int_t x = 0; |
738 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition, |
739 | 0 | no_of_nodes - marked)); |
740 | 0 | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
741 | 0 | if (!VECTOR(added)[i]) { |
742 | 0 | VECTOR(*partition)[x++] = i; |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | 0 | igraph_vector_bool_destroy(&added); |
748 | 0 | IGRAPH_FINALLY_CLEAN(1); |
749 | 0 | } |
750 | | |
751 | 51.8k | if (flow) { |
752 | | /* Initialize the backward distances, with a breadth-first search |
753 | | from the source */ |
754 | 0 | igraph_dqueue_int_t Q; |
755 | 0 | igraph_vector_int_t added; /* uses more than two values, cannot be bool */ |
756 | 0 | igraph_t flow_graph; |
757 | 0 | igraph_vector_int_t flow_edges; |
758 | 0 | igraph_bool_t dag; |
759 | |
|
760 | 0 | IGRAPH_CHECK(igraph_vector_int_init(&added, no_of_nodes)); |
761 | 0 | IGRAPH_FINALLY(igraph_vector_int_destroy, &added); |
762 | 0 | IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100)); |
763 | 0 | IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q); |
764 | |
|
765 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, source)); |
766 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0)); |
767 | 0 | VECTOR(added)[source] = 1; |
768 | 0 | while (!igraph_dqueue_int_empty(&Q)) { |
769 | 0 | const igraph_int_t actnode = igraph_dqueue_int_pop(&Q); |
770 | 0 | const igraph_int_t actdist = igraph_dqueue_int_pop(&Q); |
771 | 0 | DIST(actnode) = actdist; |
772 | |
|
773 | 0 | for (igraph_int_t i = FIRST(actnode), j = LAST(actnode); i < j; i++) { |
774 | 0 | const igraph_int_t nei = HEAD(i); |
775 | 0 | if (!VECTOR(added)[nei] && RESCAP(REV(i)) > 0.0) { |
776 | 0 | VECTOR(added)[nei] = 1; |
777 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei)); |
778 | 0 | IGRAPH_CHECK(igraph_dqueue_int_push(&Q, actdist + 1)); |
779 | 0 | } |
780 | 0 | } |
781 | 0 | } /* !igraph_dqueue_int_empty(&Q) */ |
782 | | |
783 | 0 | igraph_vector_int_destroy(&added); |
784 | 0 | igraph_dqueue_int_destroy(&Q); |
785 | 0 | IGRAPH_FINALLY_CLEAN(2); |
786 | | |
787 | | /* Reinitialize the buckets */ |
788 | 0 | igraph_buckets_clear(&buckets); |
789 | 0 | for (igraph_int_t i = 0; i < no_of_nodes; i++) { |
790 | 0 | if (EXCESS(i) > 0.0 && i != source && i != target) { |
791 | 0 | igraph_buckets_add(&buckets, DIST(i), i); |
792 | 0 | } |
793 | 0 | } |
794 | | |
795 | | /* Now we return the flow to the source */ |
796 | 0 | while (!igraph_buckets_empty(&buckets)) { |
797 | 0 | const igraph_int_t vertex = igraph_buckets_popmax(&buckets); |
798 | | |
799 | | /* DISCHARGE(vertex) comes here */ |
800 | 0 | do { |
801 | 0 | igraph_int_t i, j; |
802 | 0 | for (i = CURRENT(vertex), j = LAST(vertex); i < j; i++) { |
803 | 0 | if (RESCAP(i) > 0) { |
804 | 0 | igraph_int_t nei = HEAD(i); |
805 | |
|
806 | 0 | if (DIST(vertex) == DIST(nei) + 1) { |
807 | 0 | igraph_real_t delta = |
808 | 0 | RESCAP(i) < EXCESS(vertex) ? RESCAP(i) : EXCESS(vertex); |
809 | 0 | RESCAP(i) -= delta; |
810 | 0 | RESCAP(REV(i)) += delta; |
811 | |
|
812 | 0 | if (nei != source && EXCESS(nei) == 0.0 && |
813 | 0 | DIST(nei) != no_of_nodes) { |
814 | 0 | igraph_buckets_add(&buckets, DIST(nei), nei); |
815 | 0 | } |
816 | |
|
817 | 0 | EXCESS(nei) += delta; |
818 | 0 | EXCESS(vertex) -= delta; |
819 | |
|
820 | 0 | if (EXCESS(vertex) == 0) { |
821 | 0 | break; |
822 | 0 | } |
823 | |
|
824 | 0 | } |
825 | 0 | } |
826 | 0 | } |
827 | |
|
828 | 0 | if (i == j) { |
829 | | |
830 | | /* RELABEL(vertex) comes here */ |
831 | 0 | igraph_int_t min; |
832 | 0 | igraph_int_t min_edge = 0; |
833 | 0 | DIST(vertex) = min = no_of_nodes; |
834 | 0 | for (igraph_int_t k = FIRST(vertex), l = LAST(vertex); k < l; k++) { |
835 | 0 | if (RESCAP(k) > 0) { |
836 | 0 | if (DIST(HEAD(k)) < min) { |
837 | 0 | min = DIST(HEAD(k)); |
838 | 0 | min_edge = k; |
839 | 0 | } |
840 | 0 | } |
841 | 0 | } |
842 | |
|
843 | 0 | min++; |
844 | |
|
845 | 0 | if (min < no_of_nodes) { |
846 | 0 | DIST(vertex) = min; |
847 | 0 | CURRENT(vertex) = min_edge; |
848 | | /* Vertex is still active */ |
849 | 0 | igraph_buckets_add(&buckets, DIST(vertex), vertex); |
850 | 0 | } |
851 | | |
852 | | /* TODO: gap heuristics here ??? */ |
853 | |
|
854 | 0 | } else { |
855 | 0 | CURRENT(vertex) = FIRST(vertex); |
856 | 0 | } |
857 | |
|
858 | 0 | break; |
859 | |
|
860 | 0 | } while (true); |
861 | 0 | } |
862 | | |
863 | | /* We need to eliminate flow cycles now. Before that we check that |
864 | | there is a cycle in the flow graph. |
865 | | |
866 | | First we do a couple of DFSes from the source vertex to the |
867 | | target and factor out the paths we find. If there is no more |
868 | | path to the target, then all remaining flow must be in flow |
869 | | cycles, so we don't need it at all. |
870 | | |
871 | | Some details. 'stack' contains the whole path of the DFS, both |
872 | | the vertices and the edges, they are alternating in the stack. |
873 | | 'current' helps finding the next outgoing edge of a vertex |
874 | | quickly, the next edge of 'v' is FIRST(v)+CURRENT(v). If this |
875 | | is LAST(v), then there are no more edges to try. |
876 | | |
877 | | The 'added' vector contains 0 if the vertex was not visited |
878 | | before, 1 if it is currently in 'stack', and 2 if it is not in |
879 | | 'stack', but it was visited before. */ |
880 | |
|
881 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&flow_edges, 0); |
882 | 0 | for (igraph_int_t i = 0, j = 0; i < no_of_edges; i += 2, j++) { |
883 | 0 | const igraph_int_t pos = VECTOR(rank)[i]; |
884 | 0 | if ((capacity ? VECTOR(*capacity)[j] : 1.0) > RESCAP(pos)) { |
885 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&flow_edges, |
886 | 0 | IGRAPH_FROM(graph, j))); |
887 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&flow_edges, |
888 | 0 | IGRAPH_TO(graph, j))); |
889 | 0 | } |
890 | 0 | } |
891 | 0 | IGRAPH_CHECK(igraph_create(&flow_graph, &flow_edges, no_of_nodes, |
892 | 0 | IGRAPH_DIRECTED)); |
893 | 0 | igraph_vector_int_destroy(&flow_edges); |
894 | 0 | IGRAPH_FINALLY_CLEAN(1); |
895 | 0 | IGRAPH_FINALLY(igraph_destroy, &flow_graph); |
896 | 0 | IGRAPH_CHECK(igraph_is_dag(&flow_graph, &dag)); |
897 | 0 | igraph_destroy(&flow_graph); |
898 | 0 | IGRAPH_FINALLY_CLEAN(1); |
899 | |
|
900 | 0 | if (!dag) { |
901 | 0 | igraph_vector_int_t stack; |
902 | 0 | igraph_vector_t mycap; |
903 | |
|
904 | 0 | IGRAPH_CHECK(igraph_vector_int_init(&stack, 0)); |
905 | 0 | IGRAPH_FINALLY(igraph_vector_int_destroy, &stack); |
906 | 0 | IGRAPH_CHECK(igraph_vector_int_init(&added, no_of_nodes)); |
907 | 0 | IGRAPH_FINALLY(igraph_vector_int_destroy, &added); |
908 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&mycap, no_of_edges); |
909 | | |
910 | 0 | #define MYCAP(i) (VECTOR(mycap)[(i)]) |
911 | | |
912 | 0 | for (igraph_int_t i = 0; i < no_of_edges; i += 2) { |
913 | 0 | const igraph_int_t pos = VECTOR(rank)[i]; |
914 | 0 | const igraph_int_t pos2 = VECTOR(rank)[i + 1]; |
915 | 0 | MYCAP(pos) = (capacity ? VECTOR(*capacity)[i / 2] : 1.0) - RESCAP(pos); |
916 | 0 | MYCAP(pos2) = 0.0; |
917 | 0 | } |
918 | |
|
919 | 0 | do { |
920 | 0 | igraph_vector_int_null(¤t); |
921 | 0 | igraph_vector_int_clear(&stack); |
922 | 0 | igraph_vector_int_null(&added); |
923 | |
|
924 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&stack, -1)); |
925 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&stack, source)); |
926 | 0 | VECTOR(added)[source] = 1; |
927 | 0 | while (!igraph_vector_int_empty(&stack) && |
928 | 0 | igraph_vector_int_tail(&stack) != target) { |
929 | 0 | const igraph_int_t actnode = igraph_vector_int_tail(&stack); |
930 | 0 | igraph_int_t edge = FIRST(actnode) + CURRENT(actnode); |
931 | 0 | igraph_int_t nei; |
932 | 0 | while (edge < LAST(actnode) && MYCAP(edge) == 0.0) { |
933 | 0 | edge++; |
934 | 0 | } |
935 | 0 | nei = edge < LAST(actnode) ? HEAD(edge) : -1; |
936 | |
|
937 | 0 | if (edge < LAST(actnode) && !VECTOR(added)[nei]) { |
938 | | /* Go forward along next edge, if the vertex was not |
939 | | visited before */ |
940 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&stack, edge)); |
941 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&stack, nei)); |
942 | 0 | VECTOR(added)[nei] = 1; |
943 | 0 | CURRENT(actnode) += 1; |
944 | 0 | } else if (edge < LAST(actnode) && VECTOR(added)[nei] == 1) { |
945 | | /* We found a flow cycle, factor it out. Go back in stack |
946 | | until we find 'nei' again, determine the flow along the |
947 | | cycle. */ |
948 | 0 | igraph_real_t thisflow = MYCAP(edge); |
949 | 0 | for (igraph_int_t idx = igraph_vector_int_size(&stack) - 2; |
950 | 0 | idx >= 0 && VECTOR(stack)[idx + 1] != nei; idx -= 2) { |
951 | 0 | const igraph_int_t e = VECTOR(stack)[idx]; |
952 | 0 | const igraph_real_t rcap = e >= 0 ? MYCAP(e) : MYCAP(edge); |
953 | 0 | if (rcap < thisflow) { |
954 | 0 | thisflow = rcap; |
955 | 0 | } |
956 | 0 | } |
957 | 0 | MYCAP(edge) -= thisflow; RESCAP(edge) += thisflow; |
958 | 0 | for (igraph_int_t idx = igraph_vector_int_size(&stack) - 2; |
959 | 0 | idx >= 0 && VECTOR(stack)[idx + 1] != nei; idx -= 2) { |
960 | 0 | const igraph_int_t e = VECTOR(stack)[idx]; |
961 | 0 | if (e >= 0) { |
962 | 0 | MYCAP(e) -= thisflow; |
963 | 0 | RESCAP(e) += thisflow; |
964 | 0 | } |
965 | 0 | } |
966 | 0 | CURRENT(actnode) += 1; |
967 | 0 | } else if (edge < LAST(actnode)) { /* && VECTOR(added)[nei]==2 */ |
968 | | /* The next edge leads to a vertex that was visited before, |
969 | | but it is currently not in 'stack' */ |
970 | 0 | CURRENT(actnode) += 1; |
971 | 0 | } else { |
972 | | /* Go backward, take out the node and the edge that leads to it */ |
973 | 0 | igraph_vector_int_pop_back(&stack); |
974 | 0 | igraph_vector_int_pop_back(&stack); |
975 | 0 | VECTOR(added)[actnode] = 2; |
976 | 0 | } |
977 | 0 | } |
978 | | |
979 | | /* If non-empty, then it contains a path from source to target |
980 | | in the residual graph. We factor out this path from the flow. */ |
981 | 0 | if (!igraph_vector_int_empty(&stack)) { |
982 | 0 | const igraph_int_t pl = igraph_vector_int_size(&stack); |
983 | 0 | igraph_real_t thisflow = EXCESS(target); |
984 | 0 | for (igraph_int_t i = 2; i < pl; i += 2) { |
985 | 0 | const igraph_int_t edge = VECTOR(stack)[i]; |
986 | 0 | const igraph_real_t rcap = MYCAP(edge); |
987 | 0 | if (rcap < thisflow) { |
988 | 0 | thisflow = rcap; |
989 | 0 | } |
990 | 0 | } |
991 | 0 | for (igraph_int_t i = 2; i < pl; i += 2) { |
992 | 0 | const igraph_int_t edge = VECTOR(stack)[i]; |
993 | 0 | MYCAP(edge) -= thisflow; |
994 | 0 | } |
995 | 0 | } |
996 | |
|
997 | 0 | } while (!igraph_vector_int_empty(&stack)); |
998 | | |
999 | 0 | igraph_vector_destroy(&mycap); |
1000 | 0 | igraph_vector_int_destroy(&added); |
1001 | 0 | igraph_vector_int_destroy(&stack); |
1002 | 0 | IGRAPH_FINALLY_CLEAN(3); |
1003 | 0 | } |
1004 | | |
1005 | | /* ----------------------------------------------------------- */ |
1006 | | |
1007 | 0 | IGRAPH_CHECK(igraph_vector_resize(flow, no_of_orig_edges)); |
1008 | 0 | for (igraph_int_t i = 0, j = 0; i < no_of_edges; i += 2, j++) { |
1009 | 0 | const igraph_int_t pos = VECTOR(rank)[i]; |
1010 | 0 | VECTOR(*flow)[j] = (capacity ? VECTOR(*capacity)[j] : 1.0) - |
1011 | 0 | RESCAP(pos); |
1012 | 0 | } |
1013 | |
|
1014 | 0 | igraph_vector_int_destroy(&rank); |
1015 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1016 | 0 | } |
1017 | | |
1018 | 51.8k | igraph_dbuckets_destroy(&ibuckets); |
1019 | 51.8k | igraph_buckets_destroy(&buckets); |
1020 | 51.8k | igraph_vector_int_destroy(¤t); |
1021 | 51.8k | igraph_vector_int_destroy(&first); |
1022 | 51.8k | igraph_vector_int_destroy(&distance); |
1023 | 51.8k | igraph_vector_destroy(&excess); |
1024 | 51.8k | igraph_vector_destroy(&rescap); |
1025 | 51.8k | igraph_vector_int_destroy(&rev); |
1026 | 51.8k | igraph_vector_int_destroy(&to); |
1027 | 51.8k | igraph_dqueue_int_destroy(&bfsq); |
1028 | 51.8k | IGRAPH_FINALLY_CLEAN(10); |
1029 | | |
1030 | 51.8k | return IGRAPH_SUCCESS; |
1031 | 51.8k | } |
1032 | | |
1033 | | /** |
1034 | | * \function igraph_maxflow_value |
1035 | | * \brief Maximum flow in a network with the push/relabel algorithm. |
1036 | | * |
1037 | | * This function implements the Goldberg-Tarjan algorithm for |
1038 | | * calculating value of the maximum flow in a directed or undirected |
1039 | | * graph. The algorithm was given in Andrew V. Goldberg, Robert |
1040 | | * E. Tarjan: A New Approach to the Maximum-Flow Problem, Journal of |
1041 | | * the ACM, 35(4), 921-940, 1988 |
1042 | | * https://doi.org/10.1145/48014.61051. |
1043 | | * |
1044 | | * </para><para> |
1045 | | * The input of the function is a graph, a vector |
1046 | | * of real numbers giving the capacity of the edges and two vertices |
1047 | | * of the graph, the source and the target. A flow is a function |
1048 | | * assigning positive real numbers to the edges and satisfying two |
1049 | | * requirements: (1) the flow value is less than the capacity of the |
1050 | | * edge and (2) at each vertex except the source and the target, the |
1051 | | * incoming flow (i.e. the sum of the flow on the incoming edges) is |
1052 | | * the same as the outgoing flow (i.e. the sum of the flow on the |
1053 | | * outgoing edges). The value of the flow is the incoming flow at the |
1054 | | * target vertex. The maximum flow is the flow with the maximum |
1055 | | * value. |
1056 | | * |
1057 | | * </para><para> |
1058 | | * According to a theorem by Ford and Fulkerson |
1059 | | * (L. R. Ford Jr. and D. R. Fulkerson. Maximal flow through a |
1060 | | * network. Canadian J. Math., 8:399-404, 1956.) the maximum flow |
1061 | | * between two vertices is the same as the |
1062 | | * minimum cut between them (also called the minimum s-t cut). So \ref |
1063 | | * igraph_st_mincut_value() gives the same result in all cases as \ref |
1064 | | * igraph_maxflow_value(). |
1065 | | * |
1066 | | * </para><para> |
1067 | | * Note that the value of the maximum flow is the same as the |
1068 | | * minimum cut in the graph. |
1069 | | * |
1070 | | * \param graph The input graph, either directed or undirected. |
1071 | | * \param value Pointer to a real number, the result will be placed here. |
1072 | | * \param source The id of the source vertex. |
1073 | | * \param target The id of the target vertex. |
1074 | | * \param capacity Vector containing the capacity of the edges. If NULL, then |
1075 | | * every edge is considered to have capacity 1.0. |
1076 | | * \param stats Counts of the number of different operations |
1077 | | * preformed by the algorithm are stored here. |
1078 | | * \return Error code. |
1079 | | * |
1080 | | * Time complexity: O(|V|^3). |
1081 | | * |
1082 | | * \sa \ref igraph_maxflow() to calculate the actual flow. |
1083 | | * \ref igraph_mincut_value(), \ref igraph_edge_connectivity(), |
1084 | | * \ref igraph_vertex_connectivity() for |
1085 | | * properties based on the maximum flow. |
1086 | | */ |
1087 | | |
1088 | | igraph_error_t igraph_maxflow_value(const igraph_t *graph, igraph_real_t *value, |
1089 | | igraph_int_t source, igraph_int_t target, |
1090 | | const igraph_vector_t *capacity, |
1091 | 51.8k | igraph_maxflow_stats_t *stats) { |
1092 | | |
1093 | 51.8k | return igraph_maxflow(graph, value, /*flow=*/ NULL, /*cut=*/ NULL, |
1094 | 51.8k | /*partition=*/ NULL, /*partition1=*/ NULL, |
1095 | 51.8k | source, target, capacity, stats); |
1096 | 51.8k | } |
1097 | | |
1098 | | /** |
1099 | | * \function igraph_st_mincut_value |
1100 | | * \brief The minimum s-t cut in a graph. |
1101 | | * |
1102 | | * </para><para> The minimum s-t cut in a weighted (=valued) graph is the |
1103 | | * total minimum edge weight needed to remove from the graph to |
1104 | | * eliminate all paths from a given vertex (\p source) to |
1105 | | * another vertex (\p target). Directed paths are considered in |
1106 | | * directed graphs, and undirected paths in undirected graphs. </para> |
1107 | | * |
1108 | | * <para> The minimum s-t cut between two vertices is known to be same |
1109 | | * as the maximum flow between these two vertices. So this function |
1110 | | * calls \ref igraph_maxflow_value() to do the calculation. |
1111 | | * |
1112 | | * \param graph The input graph. |
1113 | | * \param value Pointer to a real variable, the result will be stored |
1114 | | * here. |
1115 | | * \param source The id of the source vertex. |
1116 | | * \param target The id of the target vertex. |
1117 | | * \param capacity Pointer to the capacity vector, it should contain |
1118 | | * non-negative numbers and its length should be the same the |
1119 | | * the number of edges in the graph. It can be a null pointer, then |
1120 | | * every edge has unit capacity. |
1121 | | * \return Error code. |
1122 | | * |
1123 | | * Time complexity: O(|V|^3), see also the discussion for \ref |
1124 | | * igraph_maxflow_value(), |V| is the number of vertices. |
1125 | | */ |
1126 | | |
1127 | | igraph_error_t igraph_st_mincut_value(const igraph_t *graph, igraph_real_t *value, |
1128 | | igraph_int_t source, igraph_int_t target, |
1129 | 0 | const igraph_vector_t *capacity) { |
1130 | |
|
1131 | 0 | if (source == target) { |
1132 | 0 | IGRAPH_ERROR("source and target vertices are the same", IGRAPH_EINVAL); |
1133 | 0 | } |
1134 | | |
1135 | 0 | IGRAPH_CHECK(igraph_maxflow_value(graph, value, source, target, capacity, NULL)); |
1136 | | |
1137 | 0 | return IGRAPH_SUCCESS; |
1138 | 0 | } |
1139 | | |
1140 | | /** |
1141 | | * \function igraph_st_mincut |
1142 | | * \brief Minimum cut between a source and a target vertex. |
1143 | | * |
1144 | | * Finds the edge set that has the smallest total capacity among all |
1145 | | * edge sets that disconnect the source and target vertices. |
1146 | | * |
1147 | | * </para><para>The calculation is performed using maximum flow |
1148 | | * techniques, by calling \ref igraph_maxflow(). |
1149 | | * |
1150 | | * \param graph The input graph. |
1151 | | * \param value Pointer to a real variable, the value of the cut is |
1152 | | * stored here. |
1153 | | * \param cut Pointer to an initialized vector, the edge IDs that are included |
1154 | | * in the cut are stored here. This argument is ignored if it |
1155 | | * is a null pointer. |
1156 | | * \param partition Pointer to an initialized vector, the vertex IDs of the |
1157 | | * vertices in the first partition of the cut are stored |
1158 | | * here. The first partition is always the one that contains the |
1159 | | * source vertex. This argument is ignored if it is a null pointer. |
1160 | | * \param partition2 Pointer to an initialized vector, the vertex IDs of the |
1161 | | * vertices in the second partition of the cut are stored here. |
1162 | | * The second partition is always the one that contains the |
1163 | | * target vertex. This argument is ignored if it is a null pointer. |
1164 | | * \param source Integer, the id of the source vertex. |
1165 | | * \param target Integer, the id of the target vertex. |
1166 | | * \param capacity Vector containing the capacity of the edges. If a |
1167 | | * null pointer, then every edge is considered to have capacity |
1168 | | * 1.0. |
1169 | | * \return Error code. |
1170 | | * |
1171 | | * \sa \ref igraph_maxflow(). |
1172 | | * |
1173 | | * Time complexity: see \ref igraph_maxflow(). |
1174 | | */ |
1175 | | |
1176 | | igraph_error_t igraph_st_mincut(const igraph_t *graph, igraph_real_t *value, |
1177 | | igraph_vector_int_t *cut, igraph_vector_int_t *partition, |
1178 | | igraph_vector_int_t *partition2, |
1179 | | igraph_int_t source, igraph_int_t target, |
1180 | 0 | const igraph_vector_t *capacity) { |
1181 | |
|
1182 | 0 | return igraph_maxflow(graph, value, /*flow=*/ NULL, |
1183 | 0 | cut, partition, partition2, |
1184 | 0 | source, target, capacity, NULL); |
1185 | 0 | } |
1186 | | |
1187 | | /* |
1188 | | * This is the Stoer-Wagner algorithm, it works for calculating the |
1189 | | * minimum cut for undirected graphs, for the whole graph. |
1190 | | * I.e. this is basically the edge-connectivity of the graph. |
1191 | | * It can also calculate the cut itself, not just the cut value. |
1192 | | */ |
1193 | | |
1194 | | static igraph_error_t igraph_i_mincut_undirected( |
1195 | | const igraph_t *graph, |
1196 | | igraph_real_t *res, |
1197 | | igraph_vector_int_t *partition, |
1198 | | igraph_vector_int_t *partition2, |
1199 | | igraph_vector_int_t *cut, |
1200 | 643 | const igraph_vector_t *capacity) { |
1201 | | |
1202 | 643 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1203 | 643 | igraph_int_t no_of_edges = igraph_ecount(graph); |
1204 | | |
1205 | 643 | igraph_i_cutheap_t heap; |
1206 | 643 | igraph_real_t mincut = IGRAPH_INFINITY; /* infinity */ |
1207 | 643 | igraph_int_t i; |
1208 | | |
1209 | 643 | igraph_adjlist_t adjlist; |
1210 | 643 | igraph_inclist_t inclist; |
1211 | | |
1212 | 643 | igraph_vector_int_t mergehist; |
1213 | 643 | igraph_bool_t calc_cut = partition || partition2 || cut; |
1214 | 643 | igraph_int_t act_step = 0, mincut_step = 0; |
1215 | | |
1216 | 643 | if (capacity && igraph_vector_size(capacity) != no_of_edges) { |
1217 | 0 | IGRAPH_ERROR("Invalid capacity vector size", IGRAPH_EINVAL); |
1218 | 0 | } |
1219 | | |
1220 | | /* Check if the graph is connected at all */ |
1221 | 643 | { |
1222 | 643 | igraph_vector_int_t memb; |
1223 | 643 | igraph_vector_int_t csize; |
1224 | 643 | igraph_int_t no; |
1225 | 643 | IGRAPH_VECTOR_INT_INIT_FINALLY(&memb, 0); |
1226 | 643 | IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0); |
1227 | 643 | IGRAPH_CHECK(igraph_connected_components(graph, &memb, &csize, &no, IGRAPH_WEAK)); |
1228 | 643 | if (no != 1) { |
1229 | 0 | if (res) { |
1230 | 0 | *res = 0; |
1231 | 0 | } |
1232 | 0 | if (cut) { |
1233 | 0 | igraph_vector_int_clear(cut); |
1234 | 0 | } |
1235 | 0 | if (partition) { |
1236 | 0 | igraph_int_t j = 0; |
1237 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition, |
1238 | 0 | VECTOR(csize)[0])); |
1239 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1240 | 0 | if (VECTOR(memb)[i] == 0) { |
1241 | 0 | VECTOR(*partition)[j++] = i; |
1242 | 0 | } |
1243 | 0 | } |
1244 | 0 | } |
1245 | 0 | if (partition2) { |
1246 | 0 | igraph_int_t j = 0; |
1247 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition2, no_of_nodes - |
1248 | 0 | VECTOR(csize)[0])); |
1249 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1250 | 0 | if (VECTOR(memb)[i] != 0) { |
1251 | 0 | VECTOR(*partition2)[j++] = i; |
1252 | 0 | } |
1253 | 0 | } |
1254 | 0 | } |
1255 | 0 | } |
1256 | 643 | igraph_vector_int_destroy(&csize); |
1257 | 643 | igraph_vector_int_destroy(&memb); |
1258 | 643 | IGRAPH_FINALLY_CLEAN(2); |
1259 | | |
1260 | 643 | if (no != 1) { |
1261 | 0 | return IGRAPH_SUCCESS; |
1262 | 0 | } |
1263 | 643 | } |
1264 | | |
1265 | 643 | if (calc_cut) { |
1266 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&mergehist, 0); |
1267 | 0 | IGRAPH_CHECK(igraph_vector_int_reserve(&mergehist, no_of_nodes * 2)); |
1268 | 0 | } |
1269 | | |
1270 | 643 | IGRAPH_CHECK(igraph_i_cutheap_init(&heap, no_of_nodes)); |
1271 | 643 | IGRAPH_FINALLY(igraph_i_cutheap_destroy, &heap); |
1272 | | |
1273 | 643 | IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_OUT, IGRAPH_LOOPS_ONCE)); |
1274 | 643 | IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); |
1275 | | |
1276 | 643 | IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE)); |
1277 | 643 | IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); |
1278 | | |
1279 | 38.5k | while (igraph_i_cutheap_size(&heap) >= 2) { |
1280 | | |
1281 | 37.9k | igraph_int_t last; |
1282 | 37.9k | igraph_real_t acut; |
1283 | 37.9k | igraph_int_t a, n; |
1284 | | |
1285 | 37.9k | igraph_vector_int_t *edges, *edges2; |
1286 | 37.9k | igraph_vector_int_t *neis, *neis2; |
1287 | | |
1288 | 3.73M | do { |
1289 | 3.73M | a = igraph_i_cutheap_popmax(&heap); |
1290 | | |
1291 | | /* update the weights of the active vertices connected to a */ |
1292 | 3.73M | edges = igraph_inclist_get(&inclist, a); |
1293 | 3.73M | neis = igraph_adjlist_get(&adjlist, a); |
1294 | 3.73M | n = igraph_vector_int_size(edges); |
1295 | 181M | for (i = 0; i < n; i++) { |
1296 | 177M | igraph_int_t edge = VECTOR(*edges)[i]; |
1297 | 177M | igraph_int_t to = VECTOR(*neis)[i]; |
1298 | 177M | igraph_real_t weight = capacity ? VECTOR(*capacity)[edge] : 1.0; |
1299 | 177M | igraph_i_cutheap_update(&heap, to, weight); |
1300 | 177M | } |
1301 | | |
1302 | 3.73M | } while (igraph_i_cutheap_active_size(&heap) > 1); |
1303 | | |
1304 | | /* Now, there is only one active vertex left, |
1305 | | calculate the cut of the phase */ |
1306 | 37.9k | acut = igraph_i_cutheap_maxvalue(&heap); |
1307 | 37.9k | last = igraph_i_cutheap_popmax(&heap); |
1308 | | |
1309 | 37.9k | if (acut < mincut) { |
1310 | 741 | mincut = acut; |
1311 | 741 | mincut_step = act_step; |
1312 | 741 | } |
1313 | | |
1314 | 37.9k | if (mincut == 0) { |
1315 | 0 | break; |
1316 | 0 | } |
1317 | | |
1318 | | /* And contract the last and the remaining vertex (a and last) */ |
1319 | | /* Before actually doing that, make some notes */ |
1320 | 37.9k | act_step++; |
1321 | 37.9k | if (calc_cut) { |
1322 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&mergehist, a)); |
1323 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&mergehist, last)); |
1324 | 0 | } |
1325 | | /* First remove the a--last edge if there is one, a is still the |
1326 | | last deactivated vertex */ |
1327 | 37.9k | edges = igraph_inclist_get(&inclist, a); |
1328 | 37.9k | neis = igraph_adjlist_get(&adjlist, a); |
1329 | 37.9k | n = igraph_vector_int_size(edges); |
1330 | 2.58M | for (i = 0; i < n; ) { |
1331 | 2.54M | if (VECTOR(*neis)[i] == last) { |
1332 | 381k | VECTOR(*neis)[i] = VECTOR(*neis)[n - 1]; |
1333 | 381k | VECTOR(*edges)[i] = VECTOR(*edges)[n - 1]; |
1334 | 381k | igraph_vector_int_pop_back(neis); |
1335 | 381k | igraph_vector_int_pop_back(edges); |
1336 | 381k | n--; |
1337 | 2.16M | } else { |
1338 | 2.16M | i++; |
1339 | 2.16M | } |
1340 | 2.54M | } |
1341 | | |
1342 | 37.9k | edges = igraph_inclist_get(&inclist, last); |
1343 | 37.9k | neis = igraph_adjlist_get(&adjlist, last); |
1344 | 37.9k | n = igraph_vector_int_size(edges); |
1345 | 2.49M | for (i = 0; i < n; ) { |
1346 | 2.45M | if (VECTOR(*neis)[i] == a) { |
1347 | 381k | VECTOR(*neis)[i] = VECTOR(*neis)[n - 1]; |
1348 | 381k | VECTOR(*edges)[i] = VECTOR(*edges)[n - 1]; |
1349 | 381k | igraph_vector_int_pop_back(neis); |
1350 | 381k | igraph_vector_int_pop_back(edges); |
1351 | 381k | n--; |
1352 | 2.07M | } else { |
1353 | 2.07M | i++; |
1354 | 2.07M | } |
1355 | 2.45M | } |
1356 | | |
1357 | | /* Now rewrite the edge lists of last's neighbors */ |
1358 | 37.9k | neis = igraph_adjlist_get(&adjlist, last); |
1359 | 37.9k | n = igraph_vector_int_size(neis); |
1360 | 2.10M | for (i = 0; i < n; i++) { |
1361 | 2.07M | igraph_int_t nei = VECTOR(*neis)[i]; |
1362 | 2.07M | igraph_int_t n2, j; |
1363 | 2.07M | neis2 = igraph_adjlist_get(&adjlist, nei); |
1364 | 2.07M | n2 = igraph_vector_int_size(neis2); |
1365 | 2.46G | for (j = 0; j < n2; j++) { |
1366 | 2.45G | if (VECTOR(*neis2)[j] == last) { |
1367 | 2.07M | VECTOR(*neis2)[j] = a; |
1368 | 2.07M | } |
1369 | 2.45G | } |
1370 | 2.07M | } |
1371 | | |
1372 | | /* And append the lists of last to the lists of a */ |
1373 | 37.9k | edges = igraph_inclist_get(&inclist, a); |
1374 | 37.9k | neis = igraph_adjlist_get(&adjlist, a); |
1375 | 37.9k | edges2 = igraph_inclist_get(&inclist, last); |
1376 | 37.9k | neis2 = igraph_adjlist_get(&adjlist, last); |
1377 | 37.9k | IGRAPH_CHECK(igraph_vector_int_append(edges, edges2)); |
1378 | 37.9k | IGRAPH_CHECK(igraph_vector_int_append(neis, neis2)); |
1379 | 37.9k | igraph_vector_int_clear(edges2); /* TODO: free it */ |
1380 | 37.9k | igraph_vector_int_clear(neis2); /* TODO: free it */ |
1381 | | |
1382 | | /* Remove the deleted vertex from the heap entirely */ |
1383 | 37.9k | igraph_i_cutheap_reset_undefine(&heap, last); |
1384 | 37.9k | } |
1385 | | |
1386 | 643 | *res = mincut; |
1387 | | |
1388 | 643 | igraph_inclist_destroy(&inclist); |
1389 | 643 | igraph_adjlist_destroy(&adjlist); |
1390 | 643 | igraph_i_cutheap_destroy(&heap); |
1391 | 643 | IGRAPH_FINALLY_CLEAN(3); |
1392 | | |
1393 | 643 | if (calc_cut) { |
1394 | 0 | igraph_int_t bignode = VECTOR(mergehist)[2 * mincut_step + 1]; |
1395 | 0 | igraph_int_t i, idx; |
1396 | 0 | igraph_int_t size = 1; |
1397 | 0 | igraph_bitset_t mark; |
1398 | |
|
1399 | 0 | IGRAPH_BITSET_INIT_FINALLY(&mark, no_of_nodes); |
1400 | | |
1401 | | /* first count the vertices in the partition */ |
1402 | 0 | IGRAPH_BIT_SET(mark, bignode); |
1403 | 0 | for (i = mincut_step - 1; i >= 0; i--) { |
1404 | 0 | if ( IGRAPH_BIT_TEST(mark, VECTOR(mergehist)[2 * i]) ) { |
1405 | 0 | size++; |
1406 | 0 | IGRAPH_BIT_SET(mark, VECTOR(mergehist)[2 * i + 1]); |
1407 | 0 | } |
1408 | 0 | } |
1409 | | |
1410 | | /* now store them, if requested */ |
1411 | 0 | if (partition) { |
1412 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition, size)); |
1413 | 0 | idx = 0; |
1414 | 0 | VECTOR(*partition)[idx++] = bignode; |
1415 | 0 | for (i = mincut_step - 1; i >= 0; i--) { |
1416 | 0 | if (IGRAPH_BIT_TEST(mark, VECTOR(mergehist)[2 * i])) { |
1417 | 0 | VECTOR(*partition)[idx++] = VECTOR(mergehist)[2 * i + 1]; |
1418 | 0 | } |
1419 | 0 | } |
1420 | 0 | } |
1421 | | |
1422 | | /* The other partition too? */ |
1423 | 0 | if (partition2) { |
1424 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(partition2, no_of_nodes - size)); |
1425 | 0 | idx = 0; |
1426 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1427 | 0 | if (!IGRAPH_BIT_TEST(mark, i)) { |
1428 | 0 | VECTOR(*partition2)[idx++] = i; |
1429 | 0 | } |
1430 | 0 | } |
1431 | 0 | } |
1432 | | |
1433 | | /* The edges in the cut are also requested? */ |
1434 | | /* We want as few memory allocated for 'cut' as possible, |
1435 | | so we first collect the edges in mergehist, we don't |
1436 | | need that anymore. Then we copy it to 'cut'; */ |
1437 | 0 | if (cut) { |
1438 | 0 | igraph_int_t from, to; |
1439 | 0 | igraph_vector_int_clear(&mergehist); |
1440 | 0 | for (i = 0; i < no_of_edges; i++) { |
1441 | 0 | igraph_edge(graph, i, &from, &to); |
1442 | 0 | if ((IGRAPH_BIT_TEST(mark, from) && !IGRAPH_BIT_TEST(mark, to)) || |
1443 | 0 | (IGRAPH_BIT_TEST(mark, to) && !IGRAPH_BIT_TEST(mark, from))) { |
1444 | 0 | IGRAPH_CHECK(igraph_vector_int_push_back(&mergehist, i)); |
1445 | 0 | } |
1446 | 0 | } |
1447 | 0 | igraph_vector_int_clear(cut); |
1448 | 0 | IGRAPH_CHECK(igraph_vector_int_append(cut, &mergehist)); |
1449 | 0 | } |
1450 | | |
1451 | 0 | igraph_bitset_destroy(&mark); |
1452 | 0 | igraph_vector_int_destroy(&mergehist); |
1453 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1454 | 0 | } |
1455 | | |
1456 | 643 | return IGRAPH_SUCCESS; |
1457 | 643 | } |
1458 | | |
1459 | | static igraph_error_t igraph_i_mincut_directed( |
1460 | | const igraph_t *graph, |
1461 | | igraph_real_t *value, |
1462 | | igraph_vector_int_t *partition, |
1463 | | igraph_vector_int_t *partition2, |
1464 | | igraph_vector_int_t *cut, |
1465 | 0 | const igraph_vector_t *capacity) { |
1466 | |
|
1467 | 0 | igraph_int_t i; |
1468 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1469 | 0 | igraph_real_t flow; |
1470 | 0 | igraph_real_t minmaxflow = IGRAPH_INFINITY; |
1471 | 0 | igraph_vector_int_t mypartition, mypartition2, mycut; |
1472 | 0 | igraph_vector_int_t *ppartition = NULL, *ppartition2 = NULL, *pcut = NULL; |
1473 | 0 | igraph_vector_int_t bestpartition, bestpartition2, bestcut; |
1474 | |
|
1475 | 0 | if (partition) { |
1476 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&bestpartition, 0); |
1477 | 0 | } |
1478 | 0 | if (partition2) { |
1479 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&bestpartition2, 0); |
1480 | 0 | } |
1481 | 0 | if (cut) { |
1482 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&bestcut, 0); |
1483 | 0 | } |
1484 | | |
1485 | 0 | if (partition) { |
1486 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&mypartition, 0); |
1487 | 0 | ppartition = &mypartition; |
1488 | 0 | } |
1489 | 0 | if (partition2) { |
1490 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&mypartition2, 0); |
1491 | 0 | ppartition2 = &mypartition2; |
1492 | 0 | } |
1493 | 0 | if (cut) { |
1494 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&mycut, 0); |
1495 | 0 | pcut = &mycut; |
1496 | 0 | } |
1497 | | |
1498 | 0 | for (i = 1; i < no_of_nodes; i++) { |
1499 | 0 | IGRAPH_CHECK(igraph_maxflow(graph, /*value=*/ &flow, /*flow=*/ NULL, |
1500 | 0 | pcut, ppartition, ppartition2, /*source=*/ 0, |
1501 | 0 | /*target=*/ i, capacity, NULL)); |
1502 | 0 | if (flow < minmaxflow) { |
1503 | 0 | minmaxflow = flow; |
1504 | 0 | if (cut) { |
1505 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestcut, &mycut)); |
1506 | 0 | } |
1507 | 0 | if (partition) { |
1508 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestpartition, &mypartition)); |
1509 | 0 | } |
1510 | 0 | if (partition2) { |
1511 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestpartition2, &mypartition2)); |
1512 | 0 | } |
1513 | | |
1514 | 0 | if (minmaxflow == 0) { |
1515 | 0 | break; |
1516 | 0 | } |
1517 | 0 | } |
1518 | 0 | IGRAPH_CHECK(igraph_maxflow(graph, /*value=*/ &flow, /*flow=*/ NULL, |
1519 | 0 | pcut, ppartition, ppartition2, |
1520 | 0 | /*source=*/ i, |
1521 | 0 | /*target=*/ 0, capacity, NULL)); |
1522 | 0 | if (flow < minmaxflow) { |
1523 | 0 | minmaxflow = flow; |
1524 | 0 | if (cut) { |
1525 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestcut, &mycut)); |
1526 | 0 | } |
1527 | 0 | if (partition) { |
1528 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestpartition, &mypartition)); |
1529 | 0 | } |
1530 | 0 | if (partition2) { |
1531 | 0 | IGRAPH_CHECK(igraph_vector_int_update(&bestpartition2, &mypartition2)); |
1532 | 0 | } |
1533 | | |
1534 | 0 | if (minmaxflow == 0) { |
1535 | 0 | break; |
1536 | 0 | } |
1537 | 0 | } |
1538 | 0 | } |
1539 | | |
1540 | 0 | if (value) { |
1541 | 0 | *value = minmaxflow; |
1542 | 0 | } |
1543 | |
|
1544 | 0 | if (cut) { |
1545 | 0 | igraph_vector_int_destroy(&mycut); |
1546 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1547 | 0 | } |
1548 | 0 | if (partition) { |
1549 | 0 | igraph_vector_int_destroy(&mypartition); |
1550 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1551 | 0 | } |
1552 | 0 | if (partition2) { |
1553 | 0 | igraph_vector_int_destroy(&mypartition2); |
1554 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1555 | 0 | } |
1556 | 0 | if (cut) { |
1557 | 0 | IGRAPH_CHECK(igraph_vector_int_update(cut, &bestcut)); |
1558 | 0 | igraph_vector_int_destroy(&bestcut); |
1559 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1560 | 0 | } |
1561 | 0 | if (partition2) { |
1562 | 0 | IGRAPH_CHECK(igraph_vector_int_update(partition2, &bestpartition2)); |
1563 | 0 | igraph_vector_int_destroy(&bestpartition2); |
1564 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1565 | 0 | } |
1566 | 0 | if (partition) { |
1567 | 0 | IGRAPH_CHECK(igraph_vector_int_update(partition, &bestpartition)); |
1568 | 0 | igraph_vector_int_destroy(&bestpartition); |
1569 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1570 | 0 | } |
1571 | | |
1572 | 0 | return IGRAPH_SUCCESS; |
1573 | 0 | } |
1574 | | |
1575 | | /** |
1576 | | * \function igraph_mincut |
1577 | | * \brief Calculates the minimum cut in a graph. |
1578 | | * |
1579 | | * This function calculates the minimum cut in a graph. |
1580 | | * The minimum cut is the minimum set of edges which needs to be |
1581 | | * removed to disconnect the graph. The minimum is calculated using |
1582 | | * the weights (\p capacity) of the edges, so the cut with the minimum |
1583 | | * total capacity is calculated. |
1584 | | * |
1585 | | * </para><para> For directed graphs an implementation based on |
1586 | | * calculating 2|V|-2 maximum flows is used. |
1587 | | * For undirected graphs we use the Stoer-Wagner |
1588 | | * algorithm, as described in M. Stoer and F. Wagner: A simple min-cut |
1589 | | * algorithm, Journal of the ACM, 44 585-591, 1997. |
1590 | | * |
1591 | | * </para><para> |
1592 | | * The first implementation of the actual cut calculation for |
1593 | | * undirected graphs was made by Gregory Benison, thanks Greg. |
1594 | | * |
1595 | | * \param graph The input graph. |
1596 | | * \param value Pointer to a float, the value of the cut will be |
1597 | | * stored here. |
1598 | | * \param partition Pointer to an initialized vector, the ids |
1599 | | * of the vertices in the first partition after separating the |
1600 | | * graph will be stored here. The vector will be resized as |
1601 | | * needed. This argument is ignored if it is a NULL pointer. |
1602 | | * \param partition2 Pointer to an initialized vector the ids |
1603 | | * of the vertices in the second partition will be stored here. |
1604 | | * The vector will be resized as needed. This argument is ignored |
1605 | | * if it is a NULL pointer. |
1606 | | * \param cut Pointer to an initialized vector, the IDs of the edges |
1607 | | * in the cut will be stored here. This argument is ignored if it |
1608 | | * is a NULL pointer. |
1609 | | * \param capacity A numeric vector giving the capacities of the |
1610 | | * edges. If a null pointer then all edges have unit capacity. |
1611 | | * \return Error code. |
1612 | | * |
1613 | | * \sa \ref igraph_mincut_value(), a simpler interface for calculating |
1614 | | * the value of the cut only. |
1615 | | * |
1616 | | * Time complexity: for directed graphs it is O(|V|^4), but see the |
1617 | | * remarks at \ref igraph_maxflow(). For undirected graphs it is |
1618 | | * O(|V||E|+|V|^2 log|V|). |V| and |E| are the number of vertices and |
1619 | | * edges respectively. |
1620 | | * |
1621 | | * \example examples/simple/igraph_mincut.c |
1622 | | */ |
1623 | | |
1624 | | igraph_error_t igraph_mincut(const igraph_t *graph, |
1625 | | igraph_real_t *value, |
1626 | | igraph_vector_int_t *partition, |
1627 | | igraph_vector_int_t *partition2, |
1628 | | igraph_vector_int_t *cut, |
1629 | 0 | const igraph_vector_t *capacity) { |
1630 | |
|
1631 | 0 | if (igraph_is_directed(graph)) { |
1632 | 0 | if (partition || partition2 || cut) { |
1633 | 0 | igraph_i_mincut_directed(graph, value, partition, partition2, cut, |
1634 | 0 | capacity); |
1635 | 0 | } else { |
1636 | 0 | return igraph_mincut_value(graph, value, capacity); |
1637 | 0 | } |
1638 | 0 | } else { |
1639 | 0 | IGRAPH_CHECK(igraph_i_mincut_undirected(graph, value, partition, |
1640 | 0 | partition2, cut, capacity)); |
1641 | 0 | return IGRAPH_SUCCESS; |
1642 | 0 | } |
1643 | | |
1644 | 0 | return IGRAPH_SUCCESS; |
1645 | 0 | } |
1646 | | |
1647 | | |
1648 | | static igraph_error_t igraph_i_mincut_value_undirected( |
1649 | | const igraph_t *graph, |
1650 | | igraph_real_t *res, |
1651 | 643 | const igraph_vector_t *capacity) { |
1652 | 643 | return igraph_i_mincut_undirected(graph, res, 0, 0, 0, capacity); |
1653 | 643 | } |
1654 | | |
1655 | | /** |
1656 | | * \function igraph_mincut_value |
1657 | | * \brief The minimum edge cut in a graph. |
1658 | | * |
1659 | | * </para><para> The minimum edge cut in a graph is the total minimum |
1660 | | * weight of the edges needed to remove from the graph to make the |
1661 | | * graph \em not strongly connected. (If the original graph is not |
1662 | | * strongly connected then this is zero.) Note that in undirected |
1663 | | * graphs strong connectedness is the same as weak connectedness. </para> |
1664 | | * |
1665 | | * <para> The minimum cut can be calculated with maximum flow |
1666 | | * techniques, although the current implementation does this only for |
1667 | | * directed graphs and a separate non-flow based implementation is |
1668 | | * used for undirected graphs. See Mechthild Stoer and Frank Wagner: A |
1669 | | * simple min-cut algorithm, Journal of the ACM 44 585--591, 1997. |
1670 | | * For directed graphs |
1671 | | * the maximum flow is calculated between a fixed vertex and all the |
1672 | | * other vertices in the graph and this is done in both |
1673 | | * directions. Then the minimum is taken to get the minimum cut. |
1674 | | * |
1675 | | * \param graph The input graph. |
1676 | | * \param res Pointer to a real variable, the result will be stored |
1677 | | * here. |
1678 | | * \param capacity Pointer to the capacity vector, it should contain |
1679 | | * the same number of non-negative numbers as the number of edges in |
1680 | | * the graph. If a null pointer then all edges will have unit capacity. |
1681 | | * \return Error code. |
1682 | | * |
1683 | | * \sa \ref igraph_mincut(), \ref igraph_maxflow_value(), \ref |
1684 | | * igraph_st_mincut_value(). |
1685 | | * |
1686 | | * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and |
1687 | | * O(|V|^4) for directed graphs, but see also the discussion at the |
1688 | | * documentation of \ref igraph_maxflow_value(). |
1689 | | */ |
1690 | | |
1691 | | igraph_error_t igraph_mincut_value(const igraph_t *graph, igraph_real_t *res, |
1692 | 1.05k | const igraph_vector_t *capacity) { |
1693 | | |
1694 | 1.05k | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1695 | 1.05k | igraph_real_t minmaxflow, flow; |
1696 | 1.05k | igraph_int_t i; |
1697 | | |
1698 | 1.05k | minmaxflow = IGRAPH_INFINITY; |
1699 | | |
1700 | 1.05k | if (!igraph_is_directed(graph)) { |
1701 | 643 | IGRAPH_CHECK(igraph_i_mincut_value_undirected(graph, res, capacity)); |
1702 | 643 | return IGRAPH_SUCCESS; |
1703 | 643 | } |
1704 | | |
1705 | 26.3k | for (i = 1; i < no_of_nodes; i++) { |
1706 | 25.9k | IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, 0, i, |
1707 | 25.9k | capacity, NULL)); |
1708 | 25.9k | if (flow < minmaxflow) { |
1709 | 790 | minmaxflow = flow; |
1710 | 790 | if (flow == 0) { |
1711 | 0 | break; |
1712 | 0 | } |
1713 | 790 | } |
1714 | 25.9k | IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, i, 0, |
1715 | 25.9k | capacity, NULL)); |
1716 | 25.9k | if (flow < minmaxflow) { |
1717 | 409 | minmaxflow = flow; |
1718 | 409 | if (flow == 0) { |
1719 | 0 | break; |
1720 | 0 | } |
1721 | 409 | } |
1722 | 25.9k | } |
1723 | | |
1724 | 416 | if (res) { |
1725 | 416 | *res = minmaxflow; |
1726 | 416 | } |
1727 | | |
1728 | 416 | return IGRAPH_SUCCESS; |
1729 | 416 | } |
1730 | | |
1731 | | static igraph_error_t igraph_i_st_vertex_connectivity_check_errors( |
1732 | | const igraph_t *graph, |
1733 | | igraph_int_t *res, |
1734 | | igraph_int_t source, |
1735 | | igraph_int_t target, |
1736 | | igraph_vconn_nei_t neighbors, |
1737 | | igraph_bool_t *done, |
1738 | 0 | igraph_int_t *no_conn) { |
1739 | |
|
1740 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1741 | 0 | igraph_int_t eid; |
1742 | 0 | igraph_bool_t conn; |
1743 | 0 | *done = true; |
1744 | 0 | *no_conn = 0; |
1745 | |
|
1746 | 0 | if (source == target) { |
1747 | 0 | IGRAPH_ERROR("Source and target vertices are the same.", IGRAPH_EINVAL); |
1748 | 0 | } |
1749 | | |
1750 | 0 | if (source < 0 || source >= no_of_nodes || target < 0 || target >= no_of_nodes) { |
1751 | 0 | IGRAPH_ERROR("Invalid source or target vertex.", IGRAPH_EINVAL); |
1752 | 0 | } |
1753 | | |
1754 | 0 | switch (neighbors) { |
1755 | 0 | case IGRAPH_VCONN_NEI_ERROR: |
1756 | 0 | IGRAPH_CHECK(igraph_are_adjacent(graph, source, target, &conn)); |
1757 | 0 | if (conn) { |
1758 | 0 | IGRAPH_ERROR("Source and target vertices connected.", IGRAPH_EINVAL); |
1759 | 0 | } |
1760 | 0 | break; |
1761 | 0 | case IGRAPH_VCONN_NEI_NEGATIVE: |
1762 | 0 | IGRAPH_CHECK(igraph_are_adjacent(graph, source, target, &conn)); |
1763 | 0 | if (conn) { |
1764 | 0 | *res = -1; |
1765 | 0 | return IGRAPH_SUCCESS; |
1766 | 0 | } |
1767 | 0 | break; |
1768 | 0 | case IGRAPH_VCONN_NEI_NUMBER_OF_NODES: |
1769 | 0 | IGRAPH_CHECK(igraph_are_adjacent(graph, source, target, &conn)); |
1770 | 0 | if (conn) { |
1771 | 0 | *res = no_of_nodes; |
1772 | 0 | return IGRAPH_SUCCESS; |
1773 | 0 | } |
1774 | 0 | break; |
1775 | 0 | case IGRAPH_VCONN_NEI_IGNORE: |
1776 | 0 | IGRAPH_CHECK(igraph_get_eid(graph, &eid, source, target, IGRAPH_DIRECTED, /*error=*/ false)); |
1777 | 0 | if (eid >= 0) { |
1778 | 0 | IGRAPH_CHECK(igraph_count_multiple_1(graph, no_conn, eid)); |
1779 | 0 | } |
1780 | 0 | break; |
1781 | 0 | default: |
1782 | 0 | IGRAPH_ERROR("Unknown `igraph_vconn_nei_t'.", IGRAPH_EINVAL); |
1783 | 0 | break; |
1784 | 0 | } |
1785 | 0 | *done = false; |
1786 | 0 | return IGRAPH_SUCCESS; |
1787 | 0 | } |
1788 | | |
1789 | | static igraph_error_t igraph_i_st_vertex_connectivity_directed( |
1790 | | const igraph_t *graph, |
1791 | | igraph_int_t *res, |
1792 | | igraph_int_t source, |
1793 | | igraph_int_t target, |
1794 | 0 | igraph_vconn_nei_t neighbors) { |
1795 | |
|
1796 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1797 | 0 | igraph_int_t no_of_edges; |
1798 | 0 | igraph_real_t real_res; |
1799 | 0 | igraph_t newgraph; |
1800 | 0 | igraph_int_t i, len; |
1801 | 0 | igraph_bool_t done; |
1802 | 0 | igraph_int_t no_conn; |
1803 | 0 | igraph_vector_int_t incs; |
1804 | 0 | igraph_vector_t capacity; |
1805 | |
|
1806 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_check_errors(graph, res, source, target, neighbors, &done, &no_conn)); |
1807 | 0 | if (done) { |
1808 | 0 | return IGRAPH_SUCCESS; |
1809 | 0 | } |
1810 | | |
1811 | | /* Create the new graph */ |
1812 | 0 | IGRAPH_CHECK(igraph_i_split_vertices(graph, &newgraph)); |
1813 | 0 | IGRAPH_FINALLY(igraph_destroy, &newgraph); |
1814 | | |
1815 | | /* Create the capacity vector, fill it with ones */ |
1816 | 0 | no_of_edges = igraph_ecount(&newgraph); |
1817 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&capacity, no_of_edges); |
1818 | 0 | igraph_vector_fill(&capacity, 1); |
1819 | | |
1820 | | /* "Disable" the edges incident on the input half of the source vertex |
1821 | | * and the output half of the target vertex */ |
1822 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&incs, 0); |
1823 | 0 | IGRAPH_CHECK(igraph_incident(&newgraph, &incs, source + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); |
1824 | 0 | len = igraph_vector_int_size(&incs); |
1825 | 0 | for (i = 0; i < len; i++) { |
1826 | 0 | VECTOR(capacity)[VECTOR(incs)[i]] = 0; |
1827 | 0 | } |
1828 | 0 | IGRAPH_CHECK(igraph_incident(&newgraph, &incs, target, IGRAPH_ALL, IGRAPH_LOOPS)); |
1829 | 0 | len = igraph_vector_int_size(&incs); |
1830 | 0 | for (i = 0; i < len; i++) { |
1831 | 0 | VECTOR(capacity)[VECTOR(incs)[i]] = 0; |
1832 | 0 | } |
1833 | 0 | igraph_vector_int_destroy(&incs); |
1834 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1835 | | |
1836 | | /* Do the maximum flow */ |
1837 | 0 | IGRAPH_CHECK(igraph_maxflow_value(&newgraph, &real_res, |
1838 | 0 | source, target + no_of_nodes, &capacity, NULL)); |
1839 | 0 | *res = (igraph_int_t) real_res; |
1840 | |
|
1841 | 0 | *res -= no_conn; |
1842 | |
|
1843 | 0 | igraph_vector_destroy(&capacity); |
1844 | 0 | igraph_destroy(&newgraph); |
1845 | 0 | IGRAPH_FINALLY_CLEAN(2); |
1846 | |
|
1847 | 0 | return IGRAPH_SUCCESS; |
1848 | 0 | } |
1849 | | |
1850 | | static igraph_error_t igraph_i_st_vertex_connectivity_undirected( |
1851 | | const igraph_t *graph, |
1852 | | igraph_int_t *res, |
1853 | | igraph_int_t source, |
1854 | | igraph_int_t target, |
1855 | 0 | igraph_vconn_nei_t neighbors) { |
1856 | |
|
1857 | 0 | igraph_t newgraph; |
1858 | 0 | igraph_bool_t done; |
1859 | 0 | igraph_int_t no_conn; |
1860 | |
|
1861 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_check_errors(graph, res, source, target, neighbors, &done, &no_conn)); |
1862 | 0 | if (done) { |
1863 | 0 | return IGRAPH_SUCCESS; |
1864 | 0 | } |
1865 | | |
1866 | 0 | IGRAPH_CHECK(igraph_copy(&newgraph, graph)); |
1867 | 0 | IGRAPH_FINALLY(igraph_destroy, &newgraph); |
1868 | 0 | IGRAPH_CHECK(igraph_to_directed(&newgraph, IGRAPH_TO_DIRECTED_MUTUAL)); |
1869 | | |
1870 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(&newgraph, res, |
1871 | 0 | source, target, |
1872 | 0 | IGRAPH_VCONN_NEI_IGNORE)); |
1873 | | |
1874 | 0 | igraph_destroy(&newgraph); |
1875 | 0 | IGRAPH_FINALLY_CLEAN(1); |
1876 | |
|
1877 | 0 | return IGRAPH_SUCCESS; |
1878 | 0 | } |
1879 | | |
1880 | | /** |
1881 | | * \function igraph_st_vertex_connectivity |
1882 | | * \brief The vertex connectivity of a pair of vertices. |
1883 | | * |
1884 | | * The vertex connectivity of two vertices (\p source and |
1885 | | * \p target) is the minimum number of vertices that must be |
1886 | | * deleted to eliminate all paths from \p source to \p |
1887 | | * target. Directed paths are considered in directed graphs. |
1888 | | * |
1889 | | * </para><para> |
1890 | | * The vertex connectivity of a pair is the same as the number |
1891 | | * of different (i.e. node-independent) paths from source to |
1892 | | * target, assuming no direct edges between them. |
1893 | | * |
1894 | | * </para><para> |
1895 | | * The current implementation uses maximum flow calculations to |
1896 | | * obtain the result. |
1897 | | * |
1898 | | * \param graph The input graph. |
1899 | | * \param res Pointer to an integer, the result will be stored here. |
1900 | | * \param source The id of the source vertex. |
1901 | | * \param target The id of the target vertex. |
1902 | | * \param neighbors A constant giving what to do if the two vertices |
1903 | | * are connected. Possible values: |
1904 | | * \c IGRAPH_VCONN_NEI_ERROR, stop with an error message, |
1905 | | * \c IGRAPH_VCONN_NEI_NEGATIVE, return -1. |
1906 | | * \c IGRAPH_VCONN_NEI_NUMBER_OF_NODES, return the number of nodes. |
1907 | | * \c IGRAPH_VCONN_NEI_IGNORE, ignore the fact that the two vertices |
1908 | | * are connected and calculate the number of vertices needed |
1909 | | * to eliminate all paths except for the trivial (direct) paths |
1910 | | * between \p source and \p vertex. |
1911 | | * \return Error code. |
1912 | | * |
1913 | | * Time complexity: O(|V|^3), but see the discussion at \ref |
1914 | | * igraph_maxflow_value(). |
1915 | | * |
1916 | | * \sa \ref igraph_vertex_connectivity(), |
1917 | | * \ref igraph_edge_connectivity(), |
1918 | | * \ref igraph_maxflow_value(). |
1919 | | */ |
1920 | | |
1921 | | igraph_error_t igraph_st_vertex_connectivity( |
1922 | | const igraph_t *graph, |
1923 | | igraph_int_t *res, |
1924 | | igraph_int_t source, |
1925 | | igraph_int_t target, |
1926 | 0 | igraph_vconn_nei_t neighbors) { |
1927 | |
|
1928 | 0 | if (igraph_is_directed(graph)) { |
1929 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(graph, res, |
1930 | 0 | source, target, |
1931 | 0 | neighbors)); |
1932 | 0 | } else { |
1933 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_undirected(graph, res, |
1934 | 0 | source, target, |
1935 | 0 | neighbors)); |
1936 | 0 | } |
1937 | | |
1938 | 0 | return IGRAPH_SUCCESS; |
1939 | 0 | } |
1940 | | |
1941 | | static igraph_error_t igraph_i_vertex_connectivity_directed( |
1942 | | const igraph_t *graph, |
1943 | | igraph_int_t *res, |
1944 | 0 | igraph_bool_t all_edges_are_mutual) { |
1945 | |
|
1946 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
1947 | 0 | igraph_int_t no_of_edges; |
1948 | 0 | igraph_int_t i, j, k, len; |
1949 | 0 | igraph_int_t minconn = no_of_nodes - 1, conn = 0; |
1950 | 0 | igraph_t split_graph; |
1951 | 0 | igraph_vector_t capacity; |
1952 | 0 | igraph_bool_t done; |
1953 | 0 | igraph_int_t dummy_num_connections; |
1954 | 0 | igraph_vector_int_t incs; |
1955 | 0 | igraph_real_t real_res; |
1956 | | |
1957 | | /* Create the new graph */ |
1958 | 0 | IGRAPH_CHECK(igraph_i_split_vertices(graph, &split_graph)); |
1959 | 0 | IGRAPH_FINALLY(igraph_destroy, &split_graph); |
1960 | | |
1961 | | /* Create the capacity vector, fill it with ones */ |
1962 | 0 | no_of_edges = igraph_ecount(&split_graph); |
1963 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&capacity, no_of_edges); |
1964 | 0 | igraph_vector_fill(&capacity, 1); |
1965 | |
|
1966 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&incs, 0); |
1967 | | |
1968 | 0 | for (i = 0; i < no_of_nodes; i++) { |
1969 | 0 | for (j = all_edges_are_mutual ? i + 1 : 0; j < no_of_nodes; j++) { |
1970 | 0 | if (i == j) { |
1971 | 0 | continue; |
1972 | 0 | } |
1973 | | |
1974 | 0 | IGRAPH_ALLOW_INTERRUPTION(); |
1975 | | |
1976 | | /* Check for easy cases */ |
1977 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_check_errors( |
1978 | 0 | graph, &conn, i, j, IGRAPH_VCONN_NEI_NUMBER_OF_NODES, &done, |
1979 | 0 | &dummy_num_connections |
1980 | 0 | )); |
1981 | | |
1982 | | /* 'done' will be set to true if the two vertices are already |
1983 | | * connected, and in this case 'res' will be set to the number of |
1984 | | * nodes-1. |
1985 | | * |
1986 | | * Also, since we used IGRAPH_VCONN_NEI_NUMBER_OF_NODES, |
1987 | | * dummy_num_connections will always be zero, no need to deal with |
1988 | | * it */ |
1989 | 0 | IGRAPH_ASSERT(dummy_num_connections == 0); |
1990 | | |
1991 | 0 | if (!done) { |
1992 | | /* "Disable" the edges incident on the input half of the source vertex |
1993 | | * and the output half of the target vertex */ |
1994 | 0 | IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); |
1995 | 0 | len = igraph_vector_int_size(&incs); |
1996 | 0 | for (k = 0; k < len; k++) { |
1997 | 0 | VECTOR(capacity)[VECTOR(incs)[k]] = 0; |
1998 | 0 | } |
1999 | 0 | IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL, IGRAPH_LOOPS)); |
2000 | 0 | len = igraph_vector_int_size(&incs); |
2001 | 0 | for (k = 0; k < len; k++) { |
2002 | 0 | VECTOR(capacity)[VECTOR(incs)[k]] = 0; |
2003 | 0 | } |
2004 | | |
2005 | | /* Do the maximum flow */ |
2006 | 0 | IGRAPH_CHECK(igraph_maxflow_value( |
2007 | 0 | &split_graph, &real_res, i, j + no_of_nodes, &capacity, NULL |
2008 | 0 | )); |
2009 | | |
2010 | | /* Restore the capacities */ |
2011 | 0 | IGRAPH_CHECK(igraph_incident(&split_graph, &incs, i + no_of_nodes, IGRAPH_ALL, IGRAPH_LOOPS)); |
2012 | 0 | len = igraph_vector_int_size(&incs); |
2013 | 0 | for (k = 0; k < len; k++) { |
2014 | 0 | VECTOR(capacity)[VECTOR(incs)[k]] = 1; |
2015 | 0 | } |
2016 | 0 | IGRAPH_CHECK(igraph_incident(&split_graph, &incs, j, IGRAPH_ALL, IGRAPH_LOOPS)); |
2017 | 0 | len = igraph_vector_int_size(&incs); |
2018 | 0 | for (k = 0; k < len; k++) { |
2019 | 0 | VECTOR(capacity)[VECTOR(incs)[k]] = 1; |
2020 | 0 | } |
2021 | |
|
2022 | 0 | conn = (igraph_int_t) real_res; |
2023 | 0 | } |
2024 | | |
2025 | 0 | if (conn < minconn) { |
2026 | 0 | minconn = conn; |
2027 | 0 | if (conn == 0) { |
2028 | 0 | break; |
2029 | 0 | } |
2030 | 0 | } |
2031 | 0 | } |
2032 | | |
2033 | 0 | if (minconn == 0) { |
2034 | 0 | break; |
2035 | 0 | } |
2036 | 0 | } |
2037 | | |
2038 | 0 | if (res) { |
2039 | 0 | *res = minconn; |
2040 | 0 | } |
2041 | |
|
2042 | 0 | igraph_vector_int_destroy(&incs); |
2043 | 0 | igraph_vector_destroy(&capacity); |
2044 | 0 | igraph_destroy(&split_graph); |
2045 | 0 | IGRAPH_FINALLY_CLEAN(3); |
2046 | |
|
2047 | 0 | return IGRAPH_SUCCESS; |
2048 | 0 | } |
2049 | | |
2050 | | static igraph_error_t igraph_i_vertex_connectivity_undirected( |
2051 | | const igraph_t *graph, |
2052 | 0 | igraph_int_t *res) { |
2053 | |
|
2054 | 0 | igraph_t newgraph; |
2055 | |
|
2056 | 0 | IGRAPH_CHECK(igraph_copy(&newgraph, graph)); |
2057 | 0 | IGRAPH_FINALLY(igraph_destroy, &newgraph); |
2058 | 0 | IGRAPH_CHECK(igraph_to_directed(&newgraph, IGRAPH_TO_DIRECTED_MUTUAL)); |
2059 | | |
2060 | 0 | IGRAPH_CHECK(igraph_i_vertex_connectivity_directed(&newgraph, res, /* all_edges_are_mutual = */ true)); |
2061 | | |
2062 | 0 | igraph_destroy(&newgraph); |
2063 | 0 | IGRAPH_FINALLY_CLEAN(1); |
2064 | |
|
2065 | 0 | return IGRAPH_SUCCESS; |
2066 | 0 | } |
2067 | | |
2068 | | /* Use that vertex.connectivity(G) <= edge.connectivity(G) <= min(degree(G)) |
2069 | | * |
2070 | | * Check if the graph is connected, and if its minimum degree is 1. |
2071 | | * This is sufficient to determine both the vertex and edge connectivity, |
2072 | | * which are returned in 'res'. 'found' will indicate if the connectivity |
2073 | | * could be determined. |
2074 | | */ |
2075 | | static igraph_error_t igraph_i_connectivity_checks( |
2076 | | const igraph_t *graph, |
2077 | | igraph_int_t *res, |
2078 | 2.15k | igraph_bool_t *found) { |
2079 | | |
2080 | 2.15k | igraph_bool_t conn; |
2081 | 2.15k | *found = false; |
2082 | | |
2083 | 2.15k | if (igraph_vcount(graph) == 0) { |
2084 | 0 | *res = 0; |
2085 | 0 | *found = true; |
2086 | 0 | return IGRAPH_SUCCESS; |
2087 | 0 | } |
2088 | | |
2089 | 2.15k | IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_STRONG)); |
2090 | 2.15k | if (!conn) { |
2091 | 966 | *res = 0; |
2092 | 966 | *found = true; |
2093 | 1.19k | } else { |
2094 | 1.19k | igraph_vector_int_t degree; |
2095 | 1.19k | IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, 0); |
2096 | 1.19k | if (!igraph_is_directed(graph)) { |
2097 | 721 | IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), |
2098 | 721 | IGRAPH_OUT, IGRAPH_LOOPS)); |
2099 | 721 | if (igraph_vector_int_min(°ree) == 1) { |
2100 | 78 | *res = 1; |
2101 | 78 | *found = true; |
2102 | 78 | } |
2103 | 721 | } else { |
2104 | | /* directed, check both in- & out-degree */ |
2105 | 471 | IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), |
2106 | 471 | IGRAPH_OUT, IGRAPH_LOOPS)); |
2107 | 471 | if (igraph_vector_int_min(°ree) == 1) { |
2108 | 40 | *res = 1; |
2109 | 40 | *found = true; |
2110 | 431 | } else { |
2111 | 431 | IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), |
2112 | 431 | IGRAPH_IN, IGRAPH_LOOPS)); |
2113 | 431 | if (igraph_vector_int_min(°ree) == 1) { |
2114 | 15 | *res = 1; |
2115 | 15 | *found = true; |
2116 | 15 | } |
2117 | 431 | } |
2118 | 471 | } |
2119 | 1.19k | igraph_vector_int_destroy(°ree); |
2120 | 1.19k | IGRAPH_FINALLY_CLEAN(1); |
2121 | 1.19k | } |
2122 | 2.15k | return IGRAPH_SUCCESS; |
2123 | 2.15k | } |
2124 | | |
2125 | | /** |
2126 | | * \function igraph_vertex_connectivity |
2127 | | * \brief The vertex connectivity of a graph. |
2128 | | * |
2129 | | * </para><para> The vertex connectivity of a graph is the minimum |
2130 | | * vertex connectivity along each pairs of vertices in the graph. |
2131 | | * </para> |
2132 | | * |
2133 | | * <para> The vertex connectivity of a graph is the same as group |
2134 | | * cohesion as defined in Douglas R. White and Frank Harary: The |
2135 | | * cohesiveness of blocks in social networks: node connectivity and |
2136 | | * conditional density, Sociological Methodology 31:305--359, 2001 |
2137 | | * https://doi.org/10.1111/0081-1750.00098. |
2138 | | * |
2139 | | * \param graph The input graph. |
2140 | | * \param res Pointer to an integer, the result will be stored here. |
2141 | | * \param checks Boolean constant. Whether to check if the graph is |
2142 | | * connected or complete and also the degree of the vertices. If the graph is |
2143 | | * not (strongly) connected then the connectivity is obviously zero. Otherwise |
2144 | | * if the minimum degree is 1 then the vertex connectivity is also |
2145 | | * 1. If the graph is complete, the connectivity is the vertex count |
2146 | | * minus one. It is a good idea to perform these checks, as they can be |
2147 | | * done quickly compared to the connectivity calculation itself. |
2148 | | * They were suggested by Peter McMahan, thanks Peter. |
2149 | | * \return Error code. |
2150 | | * |
2151 | | * Time complexity: O(|V|^5). |
2152 | | * |
2153 | | * \sa \ref igraph_st_vertex_connectivity(), \ref igraph_maxflow_value(), |
2154 | | * and \ref igraph_edge_connectivity(). |
2155 | | */ |
2156 | | |
2157 | | igraph_error_t igraph_vertex_connectivity( |
2158 | | const igraph_t *graph, igraph_int_t *res, |
2159 | 0 | igraph_bool_t checks) { |
2160 | |
|
2161 | 0 | igraph_bool_t ret = false; |
2162 | |
|
2163 | 0 | if (checks) { |
2164 | 0 | IGRAPH_CHECK(igraph_i_connectivity_checks(graph, res, &ret)); |
2165 | 0 | } |
2166 | | |
2167 | 0 | if (checks && !ret) { |
2168 | | /* The vertex connectivity of a complete graph is vcount-1 by definition. |
2169 | | * This check cannot be performed within igraph_i_connectivity_checks(), |
2170 | | * as that function is used both for vertex and edge connectivities. |
2171 | | * Checking if the graph is complete does not suffice to determine the |
2172 | | * edge connectivity of a complete multigraph. */ |
2173 | 0 | igraph_bool_t complete; |
2174 | 0 | IGRAPH_CHECK(igraph_is_complete(graph, &complete)); |
2175 | 0 | if (complete) { |
2176 | 0 | *res = igraph_vcount(graph) - 1; |
2177 | 0 | ret = true; |
2178 | 0 | } |
2179 | 0 | } |
2180 | | |
2181 | | /* Are we done yet? */ |
2182 | 0 | if (!ret) { |
2183 | 0 | if (igraph_is_directed(graph)) { |
2184 | 0 | IGRAPH_CHECK(igraph_i_vertex_connectivity_directed(graph, res, /* all_edges_are_mutual = */ false)); |
2185 | 0 | } else { |
2186 | 0 | IGRAPH_CHECK(igraph_i_vertex_connectivity_undirected(graph, res)); |
2187 | 0 | } |
2188 | 0 | } |
2189 | | |
2190 | 0 | return IGRAPH_SUCCESS; |
2191 | 0 | } |
2192 | | |
2193 | | /** |
2194 | | * \function igraph_st_edge_connectivity |
2195 | | * \brief Edge connectivity of a pair of vertices. |
2196 | | * |
2197 | | * The edge connectivity of two vertices (\p source and \p target) is the |
2198 | | * minimum number of edges that have to be deleted from the graph to eliminate |
2199 | | * all paths from \p source to \p target. |
2200 | | * |
2201 | | * </para><para>This function uses the maximum flow algorithm to calculate |
2202 | | * the edge connectivity. |
2203 | | * |
2204 | | * \param graph The input graph, it has to be directed. |
2205 | | * \param res Pointer to an integer, the result will be stored here. |
2206 | | * \param source The id of the source vertex. |
2207 | | * \param target The id of the target vertex. |
2208 | | * \return Error code. |
2209 | | * |
2210 | | * Time complexity: O(|V|^3). |
2211 | | * |
2212 | | * \sa \ref igraph_maxflow_value(), \ref igraph_edge_disjoint_paths(), |
2213 | | * \ref igraph_edge_connectivity(), |
2214 | | * \ref igraph_st_vertex_connectivity(), \ref |
2215 | | * igraph_vertex_connectivity(). |
2216 | | */ |
2217 | | |
2218 | | igraph_error_t igraph_st_edge_connectivity(const igraph_t *graph, |
2219 | | igraph_int_t *res, |
2220 | | igraph_int_t source, |
2221 | 0 | igraph_int_t target) { |
2222 | |
|
2223 | 0 | igraph_real_t flow; |
2224 | |
|
2225 | 0 | if (source == target) { |
2226 | 0 | IGRAPH_ERROR("The source and target vertices must be different.", IGRAPH_EINVAL); |
2227 | 0 | } |
2228 | | |
2229 | 0 | IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, NULL, NULL)); |
2230 | 0 | *res = (igraph_int_t) flow; |
2231 | |
|
2232 | 0 | return IGRAPH_SUCCESS; |
2233 | 0 | } |
2234 | | |
2235 | | |
2236 | | /** |
2237 | | * \function igraph_edge_connectivity |
2238 | | * \brief The minimum edge connectivity in a graph. |
2239 | | * |
2240 | | * </para><para> This is the minimum of the edge connectivity over all |
2241 | | * pairs of vertices in the graph. </para> |
2242 | | * |
2243 | | * <para> |
2244 | | * The edge connectivity of a graph is the same as group adhesion as |
2245 | | * defined in Douglas R. White and Frank Harary: The cohesiveness of |
2246 | | * blocks in social networks: node connectivity and conditional |
2247 | | * density, Sociological Methodology 31:305--359, 2001 |
2248 | | * https://doi.org/10.1111/0081-1750.00098. |
2249 | | * |
2250 | | * \param graph The input graph. |
2251 | | * \param res Pointer to an integer, the result will be stored here. |
2252 | | * \param checks Boolean constant. Whether to check that the graph is |
2253 | | * connected and also the degree of the vertices. If the graph is |
2254 | | * not (strongly) connected then the connectivity is obviously zero. Otherwise |
2255 | | * if the minimum degree is one then the edge connectivity is also |
2256 | | * one. It is a good idea to perform these checks, as they can be |
2257 | | * done quickly compared to the connectivity calculation itself. |
2258 | | * They were suggested by Peter McMahan, thanks Peter. |
2259 | | * \return Error code. |
2260 | | * |
2261 | | * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and |
2262 | | * O(|V|^4) for directed graphs, but see also the discussion at the |
2263 | | * documentation of \ref igraph_maxflow_value(). |
2264 | | * |
2265 | | * \sa \ref igraph_st_edge_connectivity(), \ref igraph_maxflow_value(), |
2266 | | * \ref igraph_vertex_connectivity(). |
2267 | | */ |
2268 | | |
2269 | | igraph_error_t igraph_edge_connectivity(const igraph_t *graph, |
2270 | | igraph_int_t *res, |
2271 | 2.16k | igraph_bool_t checks) { |
2272 | | |
2273 | 2.16k | igraph_bool_t ret = false; |
2274 | 2.16k | igraph_int_t number_of_nodes = igraph_vcount(graph); |
2275 | | |
2276 | | /* igraph_mincut_value returns infinity for the singleton graph, |
2277 | | * which cannot be cast to an integer. We catch this case early |
2278 | | * and postulate the edge-connectivity of this graph to be 0. |
2279 | | * This is consistent with what other software packages return. */ |
2280 | 2.16k | if (number_of_nodes <= 1) { |
2281 | 6 | *res = 0; |
2282 | 6 | return IGRAPH_SUCCESS; |
2283 | 6 | } |
2284 | | |
2285 | | /* Use that vertex.connectivity(G) <= edge.connectivity(G) <= min(degree(G)) */ |
2286 | 2.15k | if (checks) { |
2287 | 2.15k | IGRAPH_CHECK(igraph_i_connectivity_checks(graph, res, &ret)); |
2288 | 2.15k | } |
2289 | | |
2290 | 2.15k | if (!ret) { |
2291 | 1.05k | igraph_real_t real_res; |
2292 | 1.05k | IGRAPH_CHECK(igraph_mincut_value(graph, &real_res, 0)); |
2293 | 1.05k | *res = (igraph_int_t)real_res; |
2294 | 1.05k | } |
2295 | | |
2296 | 2.15k | return IGRAPH_SUCCESS; |
2297 | 2.15k | } |
2298 | | |
2299 | | /** |
2300 | | * \function igraph_edge_disjoint_paths |
2301 | | * \brief The maximum number of edge-disjoint paths between two vertices. |
2302 | | * |
2303 | | * A set of paths between two vertices is called edge-disjoint if they do not |
2304 | | * share any edges. The maximum number of edge-disjoint paths are calculated |
2305 | | * by this function using maximum flow techniques. Directed paths are |
2306 | | * considered in directed graphs. |
2307 | | * |
2308 | | * </para><para>Note that the number of disjoint paths is the same as the |
2309 | | * edge connectivity of the two vertices using uniform edge weights. |
2310 | | * |
2311 | | * \param graph The input graph, can be directed or undirected. |
2312 | | * \param res Pointer to an integer variable, the result will be |
2313 | | * stored here. |
2314 | | * \param source The id of the source vertex. |
2315 | | * \param target The id of the target vertex. |
2316 | | * \return Error code. |
2317 | | * |
2318 | | * Time complexity: O(|V|^3), but see the discussion at \ref |
2319 | | * igraph_maxflow_value(). |
2320 | | * |
2321 | | * \sa \ref igraph_vertex_disjoint_paths(), \ref |
2322 | | * igraph_st_edge_connectivity(), \ref igraph_maxflow_value(). |
2323 | | */ |
2324 | | |
2325 | | igraph_error_t igraph_edge_disjoint_paths(const igraph_t *graph, |
2326 | | igraph_int_t *res, |
2327 | | igraph_int_t source, |
2328 | 0 | igraph_int_t target) { |
2329 | |
|
2330 | 0 | igraph_real_t flow; |
2331 | |
|
2332 | 0 | if (source == target) { |
2333 | 0 | IGRAPH_ERROR("Not implemented when the source and target are the same.", |
2334 | 0 | IGRAPH_UNIMPLEMENTED); |
2335 | 0 | } |
2336 | | |
2337 | 0 | IGRAPH_CHECK(igraph_maxflow_value(graph, &flow, source, target, NULL, NULL)); |
2338 | | |
2339 | 0 | *res = (igraph_int_t) flow; |
2340 | |
|
2341 | 0 | return IGRAPH_SUCCESS; |
2342 | 0 | } |
2343 | | |
2344 | | /** |
2345 | | * \function igraph_vertex_disjoint_paths |
2346 | | * \brief Maximum number of vertex-disjoint paths between two vertices. |
2347 | | * |
2348 | | * A set of paths between two vertices is called vertex-disjoint if |
2349 | | * they share no vertices, other than the endpoints. This function computes |
2350 | | * the largest number of such paths that can be constructed between |
2351 | | * a source and a target vertex. The calculation is performed by using maximum |
2352 | | * flow techniques. |
2353 | | * |
2354 | | * </para><para> |
2355 | | * When there are no edges from the source to the target, the number of |
2356 | | * vertex-disjoint paths is the same as the vertex connectivity of |
2357 | | * the two vertices. When some edges are present, each one of them |
2358 | | * contributes one extra path. |
2359 | | * |
2360 | | * \param graph The input graph. |
2361 | | * \param res Pointer to an integer variable, the result will be |
2362 | | * stored here. |
2363 | | * \param source The id of the source vertex. |
2364 | | * \param target The id of the target vertex. |
2365 | | * \return Error code. |
2366 | | * |
2367 | | * Time complexity: O(|V|^3). |
2368 | | * |
2369 | | * \sa \ref igraph_edge_disjoint_paths(), |
2370 | | * \ref igraph_st_vertex_connectivity(), \ref igraph_maxflow_value(). |
2371 | | */ |
2372 | | |
2373 | | igraph_error_t igraph_vertex_disjoint_paths(const igraph_t *graph, |
2374 | | igraph_int_t *res, |
2375 | | igraph_int_t source, |
2376 | 0 | igraph_int_t target) { |
2377 | |
|
2378 | 0 | igraph_vector_int_t eids; |
2379 | |
|
2380 | 0 | if (source == target) { |
2381 | 0 | IGRAPH_ERROR("Not implemented when the source and target are the same.", |
2382 | 0 | IGRAPH_UNIMPLEMENTED); |
2383 | 0 | } |
2384 | | |
2385 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&eids, 4); |
2386 | 0 | IGRAPH_CHECK(igraph_get_all_eids_between(graph, &eids, source, target, /*directed*/ true)); |
2387 | | |
2388 | 0 | if (igraph_is_directed(graph)) { |
2389 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_directed(graph, res, |
2390 | 0 | source, target, |
2391 | 0 | IGRAPH_VCONN_NEI_IGNORE)); |
2392 | 0 | } else { |
2393 | 0 | IGRAPH_CHECK(igraph_i_st_vertex_connectivity_undirected(graph, res, |
2394 | 0 | source, target, |
2395 | 0 | IGRAPH_VCONN_NEI_IGNORE)); |
2396 | 0 | } |
2397 | | |
2398 | 0 | *res += igraph_vector_int_size(&eids); |
2399 | |
|
2400 | 0 | igraph_vector_int_destroy(&eids); |
2401 | 0 | IGRAPH_FINALLY_CLEAN(1); |
2402 | |
|
2403 | 0 | return IGRAPH_SUCCESS; |
2404 | 0 | } |
2405 | | |
2406 | | /** |
2407 | | * \function igraph_adhesion |
2408 | | * \brief Graph adhesion, this is (almost) the same as edge connectivity. |
2409 | | * |
2410 | | * </para><para> This quantity is defined by White and Harary in |
2411 | | * The cohesiveness of blocks in social networks: node connectivity and |
2412 | | * conditional density, (Sociological Methodology 31:305--359, 2001) |
2413 | | * and basically it is the edge connectivity of the graph |
2414 | | * with uniform edge weights. |
2415 | | * |
2416 | | * \param graph The input graph, either directed or undirected. |
2417 | | * \param res Pointer to an integer, the result will be stored here. |
2418 | | * \param checks Boolean constant. Whether to check that the graph is |
2419 | | * connected and also the degree of the vertices. If the graph is |
2420 | | * not (strongly) connected then the adhesion is obviously zero. Otherwise |
2421 | | * if the minimum degree is one then the adhesion is also |
2422 | | * one. It is a good idea to perform these checks, as they can be |
2423 | | * done quickly compared to the edge connectivity calculation itself. |
2424 | | * They were suggested by Peter McMahan, thanks Peter. |
2425 | | * \return Error code. |
2426 | | * |
2427 | | * Time complexity: O(log(|V|)*|V|^2) for undirected graphs and |
2428 | | * O(|V|^4) for directed graphs, but see also the discussion at the |
2429 | | * documentation of \ref igraph_maxflow_value(). |
2430 | | * |
2431 | | * \sa \ref igraph_cohesion(), \ref igraph_maxflow_value(), \ref |
2432 | | * igraph_edge_connectivity(), \ref igraph_mincut_value(). |
2433 | | */ |
2434 | | |
2435 | | igraph_error_t igraph_adhesion(const igraph_t *graph, |
2436 | | igraph_int_t *res, |
2437 | 0 | igraph_bool_t checks) { |
2438 | 0 | return igraph_edge_connectivity(graph, res, checks); |
2439 | 0 | } |
2440 | | |
2441 | | /** |
2442 | | * \function igraph_cohesion |
2443 | | * \brief Graph cohesion, this is the same as vertex connectivity. |
2444 | | * |
2445 | | * </para><para> This quantity was defined by White and Harary in <quote>The |
2446 | | * cohesiveness of blocks in social networks: node connectivity and |
2447 | | * conditional density</quote>, (Sociological Methodology 31:305--359, 2001) |
2448 | | * and it is the same as the vertex connectivity of a graph. |
2449 | | * |
2450 | | * \param graph The input graph. |
2451 | | * \param res Pointer to an integer variable, the result will be |
2452 | | * stored here. |
2453 | | * \param checks Boolean constant. Whether to check that the graph is |
2454 | | * connected and also the degree of the vertices. If the graph is |
2455 | | * not (strongly) connected then the cohesion is obviously zero. Otherwise |
2456 | | * if the minimum degree is one then the cohesion is also |
2457 | | * one. It is a good idea to perform these checks, as they can be |
2458 | | * done quickly compared to the vertex connectivity calculation itself. |
2459 | | * They were suggested by Peter McMahan, thanks Peter. |
2460 | | * \return Error code. |
2461 | | * |
2462 | | * Time complexity: O(|V|^4), |V| is the number of vertices. In |
2463 | | * practice it is more like O(|V|^2), see \ref igraph_maxflow_value(). |
2464 | | * |
2465 | | * \sa \ref igraph_vertex_connectivity(), \ref igraph_adhesion(), |
2466 | | * \ref igraph_maxflow_value(). |
2467 | | */ |
2468 | | |
2469 | | igraph_error_t igraph_cohesion(const igraph_t *graph, |
2470 | | igraph_int_t *res, |
2471 | 0 | igraph_bool_t checks) { |
2472 | |
|
2473 | 0 | IGRAPH_CHECK(igraph_vertex_connectivity(graph, res, checks)); |
2474 | 0 | return IGRAPH_SUCCESS; |
2475 | 0 | } |
2476 | | |
2477 | | /** |
2478 | | * \function igraph_gomory_hu_tree |
2479 | | * \brief Gomory-Hu tree of a graph. |
2480 | | * |
2481 | | * </para><para> |
2482 | | * The Gomory-Hu tree is a concise representation of the value of all the |
2483 | | * maximum flows (or minimum cuts) in a graph. The vertices of the tree |
2484 | | * correspond exactly to the vertices of the original graph in the same order. |
2485 | | * Edges of the Gomory-Hu tree are annotated by flow values. The value of |
2486 | | * the maximum flow (or minimum cut) between an arbitrary (u,v) vertex |
2487 | | * pair in the original graph is then given by the minimum flow value (i.e. |
2488 | | * edge annotation) along the shortest path between u and v in the |
2489 | | * Gomory-Hu tree. |
2490 | | * |
2491 | | * </para><para>This implementation uses Gusfield's algorithm to construct the |
2492 | | * Gomory-Hu tree. See the following paper for more details: |
2493 | | * |
2494 | | * </para><para> |
2495 | | * Reference: |
2496 | | * |
2497 | | * </para><para> |
2498 | | * Gusfield D: Very simple methods for all pairs network flow analysis. SIAM J |
2499 | | * Comput 19(1):143-155, 1990 |
2500 | | * https://doi.org/10.1137/0219009. |
2501 | | * |
2502 | | * \param graph The input graph. |
2503 | | * \param tree Pointer to an uninitialized graph; the result will be |
2504 | | * stored here. |
2505 | | * \param flows Pointer to an uninitialized vector; the flow values |
2506 | | * corresponding to each edge in the Gomory-Hu tree will |
2507 | | * be returned here. You may pass a NULL pointer here if you are |
2508 | | * not interested in the flow values. |
2509 | | * \param capacity Vector containing the capacity of the edges. If NULL, then |
2510 | | * every edge is considered to have capacity 1.0. |
2511 | | * \return Error code. |
2512 | | * |
2513 | | * Time complexity: O(|V|^4) since it performs a max-flow calculation |
2514 | | * between vertex zero and every other vertex and max-flow is |
2515 | | * O(|V|^3). |
2516 | | * |
2517 | | * \sa \ref igraph_maxflow() |
2518 | | */ |
2519 | | igraph_error_t igraph_gomory_hu_tree(const igraph_t *graph, |
2520 | | igraph_t *tree, |
2521 | | igraph_vector_t *flows, |
2522 | 0 | const igraph_vector_t *capacity) { |
2523 | |
|
2524 | 0 | igraph_int_t no_of_nodes = igraph_vcount(graph); |
2525 | 0 | igraph_int_t source, target, mid, i, n; |
2526 | 0 | igraph_vector_int_t neighbors; |
2527 | 0 | igraph_vector_t flow_values; |
2528 | 0 | igraph_vector_int_t partition; |
2529 | 0 | igraph_vector_int_t partition2; |
2530 | 0 | igraph_real_t flow_value; |
2531 | |
|
2532 | 0 | if (igraph_is_directed(graph)) { |
2533 | 0 | IGRAPH_ERROR("Gomory-Hu tree can only be calculated for undirected graphs.", |
2534 | 0 | IGRAPH_EINVAL); |
2535 | 0 | } |
2536 | | |
2537 | | /* Allocate memory */ |
2538 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&neighbors, no_of_nodes); |
2539 | 0 | IGRAPH_VECTOR_INIT_FINALLY(&flow_values, no_of_nodes); |
2540 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&partition, 0); |
2541 | 0 | IGRAPH_VECTOR_INT_INIT_FINALLY(&partition2, 0); |
2542 | | |
2543 | | /* Initialize the tree: every edge points to node 0 */ |
2544 | | /* Actually, this is done implicitly since both 'neighbors' and 'flow_values' are |
2545 | | * initialized to zero already */ |
2546 | | |
2547 | | /* For each source vertex except vertex zero... */ |
2548 | 0 | for (source = 1; source < no_of_nodes; source++) { |
2549 | 0 | IGRAPH_ALLOW_INTERRUPTION(); |
2550 | 0 | IGRAPH_PROGRESS("Gomory-Hu tree", (100.0 * (source - 1)) / (no_of_nodes - 1), 0); |
2551 | | |
2552 | | /* Find its current neighbor in the tree */ |
2553 | 0 | target = VECTOR(neighbors)[source]; |
2554 | | |
2555 | | /* Find the maximum flow between source and target */ |
2556 | 0 | IGRAPH_CHECK(igraph_maxflow(graph, &flow_value, NULL, NULL, &partition, &partition2, |
2557 | 0 | source, target, capacity, 0)); |
2558 | | |
2559 | | /* Store the maximum flow */ |
2560 | 0 | VECTOR(flow_values)[source] = flow_value; |
2561 | | |
2562 | | /* Update the tree */ |
2563 | | /* igraph_maxflow() guarantees that the source vertex will be in &partition |
2564 | | * and not in &partition2 so we need to iterate over &partition to find |
2565 | | * all the nodes that are of interest to us */ |
2566 | 0 | n = igraph_vector_int_size(&partition); |
2567 | 0 | for (i = 0; i < n; i++) { |
2568 | 0 | mid = VECTOR(partition)[i]; |
2569 | 0 | if (mid != source) { |
2570 | 0 | if (VECTOR(neighbors)[mid] == target) { |
2571 | 0 | VECTOR(neighbors)[mid] = source; |
2572 | 0 | } else if (VECTOR(neighbors)[target] == mid) { |
2573 | 0 | VECTOR(neighbors)[target] = source; |
2574 | 0 | VECTOR(neighbors)[source] = mid; |
2575 | 0 | VECTOR(flow_values)[source] = VECTOR(flow_values)[target]; |
2576 | 0 | VECTOR(flow_values)[target] = flow_value; |
2577 | 0 | } |
2578 | 0 | } |
2579 | 0 | } |
2580 | 0 | } |
2581 | | |
2582 | 0 | IGRAPH_PROGRESS("Gomory-Hu tree", 100.0, 0); |
2583 | | |
2584 | | /* Re-use the 'partition' vector as an edge list now */ |
2585 | 0 | IGRAPH_CHECK(igraph_vector_int_resize(&partition, no_of_nodes > 0 ? 2 * (no_of_nodes - 1) : 0)); |
2586 | 0 | for (i = 1, mid = 0; i < no_of_nodes; i++, mid += 2) { |
2587 | 0 | VECTOR(partition)[mid] = i; |
2588 | 0 | VECTOR(partition)[mid + 1] = VECTOR(neighbors)[i]; |
2589 | 0 | } |
2590 | | |
2591 | | /* Create the tree graph; we use igraph_subgraph_from_edges here to keep the |
2592 | | * graph and vertex attributes */ |
2593 | 0 | IGRAPH_CHECK(igraph_subgraph_from_edges(graph, tree, igraph_ess_none(), 0)); |
2594 | 0 | IGRAPH_CHECK(igraph_add_edges(tree, &partition, 0)); |
2595 | | |
2596 | | /* Free the allocated memory */ |
2597 | 0 | igraph_vector_int_destroy(&partition2); |
2598 | 0 | igraph_vector_int_destroy(&partition); |
2599 | 0 | igraph_vector_int_destroy(&neighbors); |
2600 | 0 | IGRAPH_FINALLY_CLEAN(3); |
2601 | | |
2602 | | /* Return the flow values to the caller */ |
2603 | 0 | if (flows != 0) { |
2604 | 0 | IGRAPH_CHECK(igraph_vector_update(flows, &flow_values)); |
2605 | 0 | if (no_of_nodes > 0) { |
2606 | 0 | igraph_vector_remove(flows, 0); |
2607 | 0 | } |
2608 | 0 | } |
2609 | | |
2610 | | /* Free the remaining allocated memory */ |
2611 | 0 | igraph_vector_destroy(&flow_values); |
2612 | 0 | IGRAPH_FINALLY_CLEAN(1); |
2613 | |
|
2614 | 0 | return IGRAPH_SUCCESS; |
2615 | 0 | } |