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}