rs_graph/maxflow/pushrelabel.rs
1// Copyright (c) 2015-2022 Frank Fischer <frank-fischer@shadow-soft.de>
2//
3// This program is free software: you can redistribute it and/or
4// modify it under the terms of the GNU General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful, but
9// WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>
15//
16
17//! This module implements a push relabel algorithm for solving max
18//! flow problems.
19//!
20//! This implementation uses the gap heuristic and the global
21//! relabelling heuristic.
22//!
23//! # Example
24//!
25//! ```
26//! use rs_graph::traits::*;
27//! use rs_graph::maxflow::pushrelabel;
28//! use rs_graph::Net;
29//! use rs_graph::string::{Data, from_ascii};
30//!
31//! let Data { graph: g, weights: upper, nodes } = from_ascii::<Net>(r"
32//! a---2-->b
33//! @|\ ^\
34//! / | \ | 4
35//! 5 | \ | \
36//! / | | | @
37//! s 1 1 2 t
38//! \ | | | @
39//! 5 | \ | /
40//! \ | \ | 5
41//! @v @|/
42//! c---2-->d
43//! ").unwrap();
44//!
45//! let s = g.id2node(nodes[&'s']);
46//! let t = g.id2node(nodes[&'t']);
47//! let v1 = g.id2node(nodes[&'a']);
48//! let v2 = g.id2node(nodes[&'b']);
49//! let v3 = g.id2node(nodes[&'c']);
50//! let v4 = g.id2node(nodes[&'d']);
51//!
52//! let (value, flow, mut mincut) = pushrelabel(&g, s, t, |e| upper[e.index()]);
53//!
54//! assert_eq!(value, 5);
55//! assert!(flow.iter().all(|&(e, f)| f >= 0 && f <= upper[e.index()]));
56//! assert!(g.nodes().filter(|&u| u != s && u != t).all(|u| {
57//! g.outedges(u).map(|(e,_)| flow[g.edge_id(e)].1).sum::<usize>() ==
58//! g.inedges(u).map(|(e,_)| flow[g.edge_id(e)].1).sum::<usize>()
59//! }));
60//!
61//! mincut.sort_by_key(|u| u.index());
62//! assert_eq!(mincut, vec![v1, s, v3]);
63//! ```
64//!
65//! ```
66//! use rs_graph::traits::*;
67//! use rs_graph::maxflow::pushrelabel;
68//! use rs_graph::Net;
69//! use rs_graph::string::{Data, from_ascii};
70//!
71//! let Data { graph: g, weights: upper, nodes } = from_ascii::<Net>(r"
72//! ---8-->a---10---
73//! / | \
74//! / 1 --3-- |
75//! / | / \ |
76//! / v@ \v
77//! ---->b-----9---->c----8--->d----
78//! / \ @ @^ \
79//! 18 ---6-- / / | 33
80//! / \/ / | \
81//! / /\ ----- | @
82//! s --5--- | / | t
83//! \ / | / | @
84//! 27 | ----2-|-- / /
85//! \ | / | /----8--- 7
86//! \ |/ @ | /
87//! ---->e----9-->f------6---->g----
88//! \ | @
89//! \ | /
90//! --5----->h---4---
91//! ").unwrap();
92//!
93//! let s = g.id2node(nodes[&'s']);
94//! let t = g.id2node(nodes[&'t']);
95//!
96//! assert_eq!(g.num_edges(), 18);
97//!
98//! let (value, flow, mut mincut) = pushrelabel(&g, s, t, |e| upper[e.index()]);
99//! assert_eq!(value, 29);
100//!
101//! let mincutval = g
102//! .edges()
103//! .filter(|&e| mincut.contains(&g.src(e)) && !mincut.contains(&g.snk(e)))
104//! .map(|e| upper[e.index()])
105//! .sum::<usize>();
106//! assert_eq!(value, mincutval);
107//!
108//! mincut.sort_by_key(|u| u.index());
109//! assert_eq!(mincut, "bcsef".chars().map(|v| g.id2node(nodes[&v])).collect::<Vec<_>>());
110//!
111//! assert!(flow.iter().all(|&(e, f)| f >= 0 && f <= upper[e.index()]));
112//! assert!(g.nodes().filter(|&u| u != s && u != t).all(|u| {
113//! g.outedges(u).map(|(e,_)| flow[g.edge_id(e)].1).sum::<usize>() ==
114//! g.inedges(u).map(|(e,_)| flow[g.edge_id(e)].1).sum::<usize>()
115//! }));
116//! ```
117
118use crate::traits::IndexDigraph;
119
120use std::cmp::min;
121use std::collections::VecDeque;
122
123use crate::num::traits::NumAssign;
124
125/// The push-relabel algorithm.
126///
127/// This struct contains all algorithmic working data.
128pub struct PushRelabel<'a, G, F>
129where
130 G: 'a + IndexDigraph,
131{
132 /// The underlying graph (extended to a network) the flow problem is solved
133 /// on.
134 g: &'a G,
135
136 /// Data associated with each node.
137 nodes: Vec<NodeInfo<F>>,
138 /// The list of adjacent edges for each node.
139 edges: Vec<Vec<(usize, usize)>>,
140 /// Current flow on each edge.
141 flow: Vec<F>,
142 /// The buckets containing the nodes of a specific height.
143 buckets: Vec<Bucket>,
144 /// The queue of nodes for a BFS.
145 queue: VecDeque<usize>,
146 /// The largest height of an active node.
147 largest_act: usize,
148 /// The flow value.
149 value: F,
150 /// The number of relabel operations performed during the algorithm.
151 pub cnt_relabel: usize,
152 /// Whether to use the global relabelling heuristic.
153 pub use_global_relabelling: bool,
154}
155
156/// Data associated with a node.
157#[derive(Clone)]
158struct NodeInfo<Flow> {
159 /// The current height of the node.
160 height: usize,
161 /// The excess of flow of the node.
162 excess: Flow,
163 /// The next active node in the linked list for the current height.
164 next_act: usize,
165 /// The next edge to be considered
166 iter: usize,
167}
168
169impl<Flow> NodeInfo<Flow>
170where
171 Flow: NumAssign,
172{
173 fn reset(&mut self) {
174 self.height = 0;
175 self.excess = Flow::zero();
176 self.next_act = usize::max_value();
177 self.iter = 0;
178 }
179}
180
181/// A bucket containing nodes of some height.
182#[derive(Clone)]
183struct Bucket {
184 /// The first active node of this height.
185 ///
186 /// The active nodes are kept in a singly linked list, this is the first
187 /// node in that list.
188 first_act: usize,
189 /// Number of inactive nodes of this height.
190 num_inact: usize,
191}
192
193impl Bucket {
194 /// Returns `true` if the bucket is empty.
195 ///
196 /// This means that there are neither active nor inactive nodes of the
197 /// buckets height.
198 fn is_empty(&self) -> bool {
199 self.first_act == usize::max_value() && self.num_inact == 0
200 }
201}
202
203impl<'a, G, F> PushRelabel<'a, G, F>
204where
205 G: IndexDigraph,
206 F: NumAssign + Ord + Copy,
207{
208 /// Return a new push-relabel algorithm data structure for the digraph `g`.
209 pub fn new(g: &'a G) -> Self {
210 let n = g.num_nodes();
211 PushRelabel {
212 g,
213 nodes: vec![
214 NodeInfo {
215 height: 0,
216 excess: F::zero(),
217 next_act: usize::max_value(),
218 iter: 0,
219 };
220 n
221 ],
222 edges: g
223 .nodes()
224 .map(|u| {
225 g.outedges(u)
226 .map(|(e, v)| (g.edge_id(e) << 1, g.node_id(v)))
227 .chain(g.inedges(u).map(|(e, v)| (((g.edge_id(e) << 1) | 1), g.node_id(v))))
228 .collect()
229 })
230 .collect(),
231 flow: vec![F::zero(); g.num_edges() * 2],
232 buckets: vec![
233 Bucket {
234 first_act: usize::max_value(),
235 num_inact: 0,
236 };
237 n * 2
238 ],
239 queue: VecDeque::with_capacity(n),
240 largest_act: 0,
241 value: F::zero(),
242
243 cnt_relabel: 0,
244 use_global_relabelling: true,
245 }
246 }
247
248 /// Return a reference to the underlying graph.
249 pub fn as_graph(&self) -> &'a G {
250 self.g
251 }
252
253 /// Return the flow value.
254 ///
255 /// The function returns 0 if the flow has not been computed, yet.
256 pub fn value(&self) -> F {
257 self.value
258 }
259
260 /// Return the flow value over some edge.
261 ///
262 /// The function returns 0 if the flow has not been computed, yet.
263 pub fn flow(&self, e: G::Edge<'_>) -> F {
264 self.flow[self.g.edge_id(e) << 1]
265 }
266
267 /// Return an iterator over all (edge, flow) pairs.
268 pub fn flow_iter<'b>(&'b self) -> impl Iterator<Item = (G::Edge<'a>, F)> + 'b {
269 self.g.edges().enumerate().map(move |(i, e)| (e, self.flow[i << 1]))
270 }
271
272 /// Run the push-relabel algorithm from some source to some sink node.
273 ///
274 /// The method solved the max flow problem from the source node
275 /// `src` to the sink node `snk` with the given `upper` bounds on
276 /// the edges.
277 pub fn solve<Us>(&mut self, src: G::Node<'_>, snk: G::Node<'_>, upper: Us)
278 where
279 Us: Fn(G::Edge<'a>) -> F,
280 {
281 let src = self.g.node_id(src);
282 let snk = self.g.node_id(snk);
283 assert_ne!(src, snk, "Source and sink node must not be equal");
284
285 let n = self.g.num_nodes();
286 self.cnt_relabel = 0;
287 self.init_preflow(src, upper);
288
289 self.update_heights(src, snk, false);
290
291 let mut lvl_relabel = if self.use_global_relabelling {
292 n
293 } else {
294 usize::max_value()
295 };
296
297 while self.largest_act != 0 && self.largest_act != n {
298 let l = self.largest_act;
299 let u = self.buckets[l].first_act;
300 self.buckets[l].first_act = self.nodes[u].next_act;
301 self.discharge(u);
302 if self.cnt_relabel >= lvl_relabel && self.largest_act < n {
303 self.update_heights(src, snk, false);
304 lvl_relabel += n;
305 }
306
307 if self.largest_act == 0 {
308 // End of phase I. Compute exact labels one last time, this time
309 // from the source.
310 self.update_heights(src, snk, true);
311 }
312 }
313
314 self.value = self.nodes[snk].excess;
315 }
316
317 /// Return the minimal cut associated with the last maximum flow.
318 pub fn mincut(&self) -> Vec<G::Node<'a>> {
319 // The minimal cut consists of the nodes with height >= n
320 let n = self.g.num_nodes();
321 self.g
322 .nodes()
323 .filter(|u| self.nodes[self.g.node_id(*u)].height >= n)
324 .collect()
325 }
326
327 /// Initialize preflow algorithm.
328 ///
329 /// All edges leaving the source node are saturated, the source's
330 /// height is set to `n`, all other heights are set to `0`.
331 fn init_preflow<Us>(&mut self, src: usize, upper: Us)
332 where
333 Us: Fn(G::Edge<'a>) -> F,
334 {
335 for node in &mut self.nodes {
336 node.reset();
337 }
338 for (e, flw) in self.flow.iter_mut().enumerate() {
339 if e & 1 == 0 {
340 *flw = F::zero();
341 } else {
342 *flw = upper(self.g.id2edge(e >> 1));
343 }
344 }
345
346 // send maximal flow out of source
347 for &(e, v) in &self.edges[src] {
348 let f = e ^ 1;
349 let ub = self.flow[f];
350 self.flow[e] = ub;
351 self.flow[f] = F::zero();
352 self.nodes[v].excess += ub;
353 }
354
355 self.nodes[src].height = self.g.num_nodes();
356 }
357
358 /// Compute exact labels.
359 ///
360 /// This function does a bfs from the sink (phase I) or source (phase II) to
361 /// compute exact labels.
362 fn update_heights(&mut self, src: usize, snk: usize, from_src: bool) {
363 let n = self.g.num_nodes();
364
365 // Put all nodes to height 2*n
366 for node in &mut self.nodes {
367 node.height = n + n;
368 // we need to reset the iterators for correctness
369 node.iter = 0;
370 }
371
372 // Except for the source and and the sink
373 self.nodes[snk].height = 0;
374 self.nodes[src].height = n;
375
376 for b in if from_src {
377 &mut self.buckets[n + 1..]
378 } else {
379 &mut self.buckets[..n]
380 } {
381 b.first_act = usize::max_value();
382 b.num_inact = 0;
383 }
384
385 // source and sink count as inactive, just in case
386 self.buckets[0].num_inact = 1;
387 self.buckets[n].num_inact = 1;
388
389 // find correct labels by BFS from sink
390 self.queue.clear();
391 self.queue.push_back(snk);
392
393 self.largest_act = 0;
394 loop {
395 while let Some(v) = self.queue.pop_front() {
396 let h = self.nodes[v].height + 1;
397 for &(e, u) in &self.edges[v] {
398 let udata = &mut self.nodes[u];
399 if udata.height > h && self.flow[e] > F::zero() {
400 udata.height = h;
401 self.queue.push_back(u);
402 // add node to appropriate bucket
403 if udata.excess > F::zero() {
404 // u is active
405 udata.next_act = self.buckets[h].first_act;
406 self.buckets[h].first_act = u;
407 self.largest_act = h;
408 debug_assert!(from_src || self.largest_act < n);
409 } else {
410 // u is inactive
411 self.buckets[h].num_inact += 1;
412 }
413 }
414 }
415 }
416 // possibly start again from the source to find the perfect
417 // labels for phase II
418 if self.largest_act >= n || !from_src {
419 break;
420 }
421 self.largest_act = n;
422 self.queue.push_back(src);
423 }
424 }
425
426 /// Discharges node `u`.
427 ///
428 /// This function does a sequence of push and relabel operations for an
429 /// active node `u` until its excess reaches 0.
430 ///
431 /// In phase I, the function may also with `u` having nonzero excess if the
432 /// height of u is at least `n`. In this case `u` gets disconnected from the
433 /// sink and will not be considered again until phase II.
434 #[allow(clippy::many_single_char_names)]
435 fn discharge(&mut self, u: usize) {
436 let n = self.g.num_nodes();
437
438 loop {
439 // The minimal height of the reachable neighbors.
440 // If `u` gets relabelled, it gets height `n_neighbor + 1`.
441 let mut h_neighbor = 2 * n;
442 let h_u = self.nodes[u].height;
443 let edges = &self.edges[u];
444
445 // Start at current edge (if any) or restart at beginning.
446 let first_iter = self.nodes[u].iter;
447 let mut cur = first_iter;
448
449 loop {
450 let (e, v) = edges[cur];
451 // skip non-admissible edges
452 let f = e ^ 1;
453 if !self.flow[f].is_zero() {
454 if h_u == self.nodes[v].height + 1 {
455 // Push along edge e
456 let df = min(self.nodes[u].excess, self.flow[f]);
457
458 debug_assert_eq!(h_u, self.nodes[v].height + 1);
459 debug_assert!(df > F::zero());
460
461 if self.nodes[v].excess.is_zero() {
462 // sink node becomes active
463 let h = self.nodes[v].height;
464 self.nodes[v].next_act = self.buckets[h].first_act;
465 self.buckets[h].first_act = v;
466 debug_assert!(self.buckets[h].num_inact > 0, "height:{} n:{}", h, n);
467 self.buckets[h].num_inact -= 1;
468 }
469
470 self.flow[e] += df;
471 self.flow[f] -= df;
472 self.nodes[u].excess -= df;
473 self.nodes[v].excess += df;
474
475 // check if node is fully discharged
476 if self.nodes[u].excess.is_zero() {
477 // node is inactive now
478 self.buckets[h_u].num_inact += 1;
479 self.largest_act = (0..h_u + 1)
480 .rev()
481 .find(|&h| self.buckets[h].first_act != usize::max_value())
482 .unwrap_or(0);
483 // save current edge
484 self.nodes[u].iter = cur;
485 return;
486 }
487 } else {
488 h_neighbor = h_neighbor.min(self.nodes[v].height);
489 }
490 }
491
492 // edge is full, go to next
493 cur += 1;
494 if cur == edges.len() {
495 break;
496 }
497 }
498
499 // Update new height for neighbors before `first_edge`.
500 self.nodes[u].iter = 0;
501 for &(e, v) in &edges[..first_iter] {
502 if !self.flow[e ^ 1].is_zero() {
503 h_neighbor = h_neighbor.min(self.nodes[v].height);
504 }
505 }
506
507 // we ran out of admissible edges but node still has positive excess, relabel node
508 if !self.relabel(u, h_neighbor + 1) {
509 // node has not got active again (i.e. its label is too high now), stop
510 break;
511 }
512 }
513 }
514
515 /// The relabel operation.
516 ///
517 /// Relabel `u` to height `h_new`.
518 ///
519 /// The function returns `true` iff the node remains active (i.e. if it
520 /// could be discharged again).
521 ///
522 /// In phase I the function returns `false` if the height of `u` gets at
523 /// least `n`. In this case `u` is disconnected from the sink and will not
524 /// be discharged again until phase II.
525 fn relabel(&mut self, u: usize, h_new: usize) -> bool {
526 debug_assert!(self.nodes[u].excess > F::zero());
527
528 // count number of relabellings
529 self.cnt_relabel += 1;
530
531 let n = self.g.num_nodes();
532 let h_old = self.nodes[u].height;
533 debug_assert_eq!(
534 h_new,
535 self.edges[u]
536 .iter()
537 .filter_map(|&(e, v)| {
538 if self.flow[e ^ 1] > F::zero() {
539 Some(self.nodes[v].height)
540 } else {
541 None
542 }
543 })
544 .min()
545 .unwrap()
546 + 1
547 );
548
549 debug_assert!(h_new > h_old);
550
551 // *** The GAP heuristic ***
552
553 // Check if we are still in phase I.
554 if h_old < n {
555 let mut h_new = h_new;
556
557 // Test whether the node's old bucket is empty now.
558 // This would create a gap.
559 if self.buckets[h_old].is_empty() {
560 // It is empty now, so u is disconnected from the sink.
561 // We remove all nodes with higher label from all buckets.
562 for h in h_old + 1..n {
563 if self.buckets[h].is_empty() {
564 // all higher buckets are empty, too
565 break;
566 }
567 self.buckets[h].first_act = usize::max_value();
568 self.buckets[h].num_inact = 0;
569 }
570
571 // Relabel all nodes to n+1
572 //
573 // Actually, this is not very fast. We could keep a list of *all*
574 // nodes of each height, then this would be possible in O(1)
575 // amortized time (each node is relabelled to n+1 at most once).
576 //
577 // However, because each node can be the cause of the disconnection
578 // at most once (when it is relabelled and creates a gap), the
579 // running time is at most O(n^2) anyway.
580 for node in &mut self.nodes {
581 if h_old < node.height {
582 node.height = n + 1;
583 }
584 }
585
586 // The node has now label n + 1.
587 h_new = n + 1;
588 }
589
590 // This node has now a too large label for phase I.
591 // There is no need to discharge the node again. Instead we look for
592 // a new active node.
593 if h_new >= n {
594 debug_assert_eq!(self.largest_act, h_old);
595
596 self.nodes[u].height = h_new;
597
598 // Find largest remaining bucket with an active node.
599 //
600 // Phase I ends once this reaches 0.
601 self.largest_act = (0..h_old + 1)
602 .rev()
603 .find(|&h| self.buckets[h].first_act != usize::max_value())
604 .unwrap_or(0);
605
606 // The current node has been relabelled to n+1, so no further discharge is necessary.
607 return false;
608 }
609 }
610
611 // The node remains active, is must have the largest height now.
612 self.nodes[u].height = h_new;
613 self.largest_act = h_new;
614 true
615 }
616}
617
618#[cfg(test)]
619mod tests {
620 use crate::maxflow::pushrelabel;
621 use crate::traits::*;
622 use crate::{Buildable, Builder, Net};
623
624 #[test]
625 fn test_pushrelabel() {
626 let mut g = Net::new_builder();
627 let mut upper = vec![];
628 let s = g.add_node();
629 let t = g.add_node();
630 let v1 = g.add_node();
631 let v2 = g.add_node();
632 let v3 = g.add_node();
633 let v4 = g.add_node();
634 g.add_edge(s, v1);
635 upper.push(15);
636 g.add_edge(s, v3);
637 upper.push(10);
638 g.add_edge(v1, v2);
639 upper.push(6);
640 g.add_edge(v1, v3);
641 upper.push(7);
642 g.add_edge(v2, t);
643 upper.push(5);
644 g.add_edge(v2, v4);
645 upper.push(2);
646 g.add_edge(v3, v2);
647 upper.push(11);
648 g.add_edge(v3, v4);
649 upper.push(4);
650 g.add_edge(v4, v2);
651 upper.push(4);
652 g.add_edge(v4, t);
653 upper.push(20);
654
655 let g = g.into_graph();
656 let (value, flow, _) = pushrelabel(&g, s, t, |e| upper[e.index()]);
657
658 assert_eq!(value, 11);
659 assert!(flow.iter().all(|&(e, f)| f >= 0 && f <= upper[e.index()]));
660 assert!(g.nodes().filter(|&u| u != s && u != t).all(|u| g
661 .outedges(u)
662 .map(|(e, _)| flow[e.index()].1)
663 .sum::<isize>()
664 == g.inedges(u).map(|(e, _)| flow[e.index()].1).sum::<isize>()));
665 }
666}
667
668/// Solve the maxflow problem using the push-relabel algorithm.
669///
670/// The function solves the max flow problem from the source nodes
671/// `src` to the sink node `snk` with the given `upper` bounds on
672/// the edges.
673///
674/// The function returns the flow value, the flow on each edge and the
675/// nodes in a minimal cut.
676pub fn pushrelabel<'a, G, F, Us>(
677 g: &'a G,
678 src: G::Node<'_>,
679 snk: G::Node<'_>,
680 upper: Us,
681) -> (F, Vec<(G::Edge<'a>, F)>, Vec<G::Node<'a>>)
682where
683 G: IndexDigraph,
684 F: 'a + NumAssign + Ord + Copy,
685 Us: Fn(G::Edge<'_>) -> F,
686{
687 let mut maxflow = PushRelabel::new(g);
688 maxflow.solve(src, snk, upper);
689 (maxflow.value(), maxflow.flow_iter().collect(), maxflow.mincut())
690}