use crate::maxflow::MaxFlow;
use crate::adapters::Network;
use crate::traits::{Directed, GraphIterator, GraphSize, GraphType, IndexDigraph, IndexGraph};
use crate::vec::{EdgeVec, NodeVec};
use std::cmp::min;
use std::collections::VecDeque;
use crate::num::traits::NumAssign;
pub struct PushRelabel<'a, G, F>
where
G: 'a + IndexDigraph<'a>,
{
g: Network<'a, G>,
nodes: NodeVec<'a, &'a G, NodeInfo<'a, G, F>>,
flow: EdgeVec<'a, Network<'a, G>, F>,
buckets: Vec<Bucket<G::Node>>,
queue: VecDeque<G::Node>,
largest_act: usize,
value: F,
pub cnt_relabel: usize,
pub use_global_relabelling: bool,
}
struct NodeInfo<'a, G, Flow>
where
G: IndexDigraph<'a>,
{
height: usize,
excess: Flow,
next_act: Option<G::Node>,
current_edge: Option<(
<Network<'a, G> as GraphType<'a>>::Edge,
<Network<'a, G> as Directed<'a>>::OutIt,
)>,
}
#[derive(Clone)]
struct Bucket<Node> {
first_act: Option<Node>,
num_inact: usize,
}
impl<Node> Bucket<Node> {
fn is_empty(&self) -> bool {
self.first_act.is_none() && self.num_inact == 0
}
}
impl<'a, G, F> MaxFlow<'a> for PushRelabel<'a, G, F>
where
G: IndexDigraph<'a>,
F: NumAssign + Ord + Copy,
{
type Graph = G;
type Flow = F;
fn new(g: &'a G) -> Self {
let n = g.num_nodes();
PushRelabel {
g: Network::new(g),
nodes: NodeVec::new_with(g, |_| NodeInfo {
height: 0,
excess: F::zero(),
next_act: None,
current_edge: None,
}),
flow: EdgeVec::new(Network::new(g), F::zero()),
buckets: vec![
Bucket {
first_act: None,
num_inact: 0,
};
n * 2
],
queue: VecDeque::with_capacity(n),
largest_act: 0,
value: F::zero(),
cnt_relabel: 0,
use_global_relabelling: true,
}
}
fn as_graph(&self) -> &'a Self::Graph {
self.g.as_graph()
}
fn value(&self) -> F {
self.value
}
fn flow(&self, e: G::Edge) -> F {
self.flow[self.g.from_edge(e)]
}
fn solve<Us>(&mut self, src: G::Node, snk: G::Node, upper: Us)
where
Us: Fn(G::Edge) -> Self::Flow,
{
assert_ne!(
self.g.node_id(src),
self.g.node_id(snk),
"Source and sink node must not be equal"
);
let n = self.g.num_nodes();
self.cnt_relabel = 0;
self.init_preflow(src, upper);
self.update_heights(src, snk, false);
let mut lvl_relabel = if self.use_global_relabelling {
n
} else {
usize::max_value()
};
while self.largest_act != 0 && self.largest_act != n {
let l = self.largest_act;
let u = self.buckets[l].first_act.unwrap();
self.buckets[l].first_act = self.nodes[u].next_act;
self.discharge(u);
if self.cnt_relabel >= lvl_relabel && self.largest_act < n {
self.update_heights(src, snk, false);
lvl_relabel += n;
}
if self.largest_act == 0 {
self.update_heights(src, snk, true);
}
}
self.value = self.nodes[snk].excess;
}
fn mincut(&self) -> Vec<G::Node> {
let n = self.g.num_nodes();
self.g.nodes().filter(|u| self.nodes[*u].height >= n).collect()
}
}
impl<'a, G, F> PushRelabel<'a, G, F>
where
G: IndexDigraph<'a>,
F: NumAssign + Ord + Copy,
{
fn init_preflow<Us>(&mut self, src: G::Node, upper: Us)
where
Us: Fn(G::Edge) -> F,
{
for u in self.g.nodes() {
self.nodes[u] = NodeInfo {
height: 0,
excess: F::zero(),
next_act: None,
current_edge: None,
};
}
for e in self.g.edges() {
if e.is_forward() {
self.flow[e] = F::zero();
} else {
self.flow[e] = upper(e.edge());
}
}
for (e, v) in self.g.outedges(src) {
let f = e.reverse();
let ub = self.flow[f];
self.flow[e] = ub;
self.flow[f] = F::zero();
self.nodes[v].excess += ub;
}
self.nodes[src].height = self.g.num_nodes();
}
fn update_heights(&mut self, src: G::Node, snk: G::Node, from_src: bool) {
let n = self.g.num_nodes();
for u in self.g.nodes() {
self.nodes[u].height = n + n;
self.nodes[u].current_edge = None;
}
self.nodes[snk].height = 0;
self.nodes[src].height = n;
for b in if from_src {
&mut self.buckets[n + 1..]
} else {
&mut self.buckets[..n]
} {
b.first_act = None;
b.num_inact = 0;
}
self.buckets[0].num_inact = 1;
self.buckets[n].num_inact = 1;
self.queue.clear();
self.queue.push_back(snk);
self.largest_act = 0;
loop {
while let Some(v) = self.queue.pop_front() {
let h = self.nodes[v].height + 1;
for (e, u) in self.g.outedges(v) {
let udata = &mut self.nodes[u];
if udata.height > h && self.flow[e] > F::zero() {
udata.height = h;
self.queue.push_back(u);
if udata.excess > F::zero() {
udata.next_act = self.buckets[h].first_act;
self.buckets[h].first_act = Some(u);
self.largest_act = h;
debug_assert!(from_src || self.largest_act < n);
} else {
self.buckets[h].num_inact += 1;
}
}
}
}
if self.largest_act >= n || !from_src {
break;
}
self.largest_act = n;
self.queue.push_back(src);
}
}
#[allow(clippy::many_single_char_names)]
fn discharge(&mut self, u: G::Node) {
let n = self.g.num_nodes();
loop {
let mut h_neighbor = 2 * n;
let h_u = self.nodes[u].height;
let (first_edge, mut rest) = if let Some((e, r)) = self.nodes[u].current_edge.take() {
((e, self.g.snk(e)), r)
} else {
let mut it = self.g.out_iter(u);
if let Some(e) = it.next(&self.g) {
(e, it)
} else {
return;
}
};
let mut cur = first_edge;
loop {
let (e, v) = cur;
let f = e.reverse();
if !self.flow[f].is_zero() {
if h_u == self.nodes[v].height + 1 {
let df = min(self.nodes[u].excess, self.flow[f]);
debug_assert_eq!(h_u, self.nodes[v].height + 1);
debug_assert!(df > F::zero());
if self.nodes[v].excess.is_zero() {
let h = self.nodes[v].height;
self.nodes[v].next_act = self.buckets[h].first_act;
self.buckets[h].first_act = Some(v);
debug_assert!(self.buckets[h].num_inact > 0, "height:{} n:{}", h, n);
self.buckets[h].num_inact -= 1;
}
self.flow[e] += df;
self.flow[f] -= df;
self.nodes[u].excess -= df;
self.nodes[v].excess += df;
if self.nodes[u].excess.is_zero() {
self.buckets[h_u].num_inact += 1;
self.largest_act = (0..h_u + 1)
.rev()
.find(|&h| self.buckets[h].first_act.is_some())
.unwrap_or(0);
self.nodes[u].current_edge = Some((cur.0, rest));
return;
}
} else {
h_neighbor = h_neighbor.min(self.nodes[v].height);
}
}
if let Some(e) = rest.next(&self.g) {
cur = e
} else {
break;
}
}
let end = first_edge.0;
for (e, v) in self.g.outedges(u) {
if e == end {
break;
}
if !self.flow[e.reverse()].is_zero() {
h_neighbor = h_neighbor.min(self.nodes[v].height);
}
}
if !self.relabel(u, h_neighbor + 1) {
break;
}
}
}
fn relabel(&mut self, u: G::Node, h_new: usize) -> bool {
debug_assert!(self.nodes[u].excess > F::zero());
self.cnt_relabel += 1;
let n = self.g.num_nodes();
let h_old = self.nodes[u].height;
debug_assert_eq!(
h_new,
self.g
.outedges(u)
.filter_map(|(e, v)| {
if self.flow[e.reverse()] > F::zero() {
Some(self.nodes[v].height)
} else {
None
}
})
.min()
.unwrap()
+ 1
);
debug_assert!(h_new > h_old);
if h_old < n {
let mut h_new = h_new;
if self.buckets[h_old].is_empty() {
for h in h_old + 1..n {
if self.buckets[h].is_empty() {
break;
}
self.buckets[h].first_act = None;
self.buckets[h].num_inact = 0;
}
for u in self.g.nodes() {
if h_old < self.nodes[u].height {
self.nodes[u].height = n + 1;
}
}
h_new = n + 1;
}
if h_new >= n {
debug_assert_eq!(self.largest_act, h_old);
self.nodes[u].height = h_new;
self.largest_act = (0..h_old + 1)
.rev()
.find(|&h| self.buckets[h].first_act.is_some())
.unwrap_or(0);
return false;
}
}
self.nodes[u].height = h_new;
self.largest_act = h_new;
true
}
}
#[cfg(test)]
mod tests {
use crate::maxflow::pushrelabel;
use crate::traits::*;
use crate::{Buildable, Builder, Net};
#[test]
fn test_pushrelabel() {
let mut g = Net::new_builder();
let mut upper = vec![];
let s = g.add_node();
let t = g.add_node();
let v1 = g.add_node();
let v2 = g.add_node();
let v3 = g.add_node();
let v4 = g.add_node();
g.add_edge(s, v1);
upper.push(15);
g.add_edge(s, v3);
upper.push(10);
g.add_edge(v1, v2);
upper.push(6);
g.add_edge(v1, v3);
upper.push(7);
g.add_edge(v2, t);
upper.push(5);
g.add_edge(v2, v4);
upper.push(2);
g.add_edge(v3, v2);
upper.push(11);
g.add_edge(v3, v4);
upper.push(4);
g.add_edge(v4, v2);
upper.push(4);
g.add_edge(v4, t);
upper.push(20);
let g = g.into_graph();
let (value, flow, _) = pushrelabel(&g, s, t, |e| upper[e.index()]);
assert_eq!(value, 11);
assert!(g.edges().all(|e| flow[e] >= 0 && flow[e] <= upper[e.index()]));
assert!(g
.nodes()
.filter(|&u| u != s && u != t)
.all(|u| g.outedges(u).map(|(e, _)| flow[e]).sum::<isize>()
== g.inedges(u).map(|(e, _)| flow[e]).sum::<isize>()));
}
}