use std::{
collections::{HashMap, VecDeque},
fmt::Debug,
hash::Hash,
iter::Sum,
ops::{AddAssign, SubAssign},
};
use num::Zero;
use crate::{
ArcInfo, ArcStorage, Network,
algorithms::{Distance, next_admissible_arc},
node_storage::NodeStorage,
search::Direction,
};
pub fn preflow_push<I, T, NodeStore, ArcStore>(
network: &Network<I, (), T, NodeStore, ArcStore>,
source: &I,
sink: &I,
) -> (T, Network<I, (), T, NodeStore, ArcStore>)
where
ArcStore:
ArcStorage<I, T> + FromIterator<ArcInfo<I, T>> + Clone + IntoIterator<Item = ArcInfo<I, T>>,
NodeStore: NodeStorage<I, ()> + Clone + IntoIterator<Item = (I, ())> + FromIterator<(I, ())>,
I: Hash + Eq + Copy,
T: Zero + Sum + Copy + Ord + Eq + AddAssign + SubAssign,
{
let n = network.n_nodes();
let mut flows: Network<I, PfpNode<T>, T, HashMap<I, PfpNode<T>>, ArcStore> = (*network)
.clone()
.map_nodes(|(idx, _attrs)| {
if &idx == source {
(idx, PfpNode::new(Distance::Finite(n), Distance::Infinite))
} else {
(idx, PfpNode::new(Distance::Infinite, Distance::zero()))
}
})
.expect("By construction, this is valid");
flows.node_mut(sink).expect("Should exist").distance_label = Distance::zero();
let bfs_nodes: Vec<I> = flows
.bfs(sink, Direction::Reverse)
.skip(1)
.copied()
.collect();
for node in bfs_nodes {
let distance_to_node = flows
.forward_arcs(&node)
.filter_map(|a| flows.node(&a.head))
.map(PfpNode::label)
.map(|d| d + 1)
.min()
.unwrap_or(Distance::Infinite);
flows.node_mut(&node).expect("Should exist").distance_label = distance_to_node;
}
flows
.node_mut(source)
.expect("Node should exist")
.distance_label = Distance::Finite(flows.n_nodes());
let mut next_nodes: VecDeque<I> = VecDeque::new();
let arcs_from_source: Vec<ArcInfo<I, T>> = flows.forward_arcs(source).cloned().collect();
for arc in arcs_from_source {
pfp_push(&mut flows, &arc, &mut next_nodes, sink, source);
}
while let Some(node_id) = next_nodes.pop_front() {
while !flows.node(&node_id).expect("Should exist").excess.is_zero() {
if let Some(arc) = next_admissible_arc(&flows, PfpNode::label, &node_id).cloned() {
pfp_push(&mut flows, &arc, &mut next_nodes, sink, source);
} else {
let new_label = flows
.forward_arcs(&node_id)
.filter_map(|arc| flows.node(&arc.head))
.map(|n| n.distance_label + 1)
.min()
.unwrap_or(Distance::Infinite);
flows
.node_mut(&node_id)
.expect("Should exist")
.distance_label = new_label;
if !flows.node(&node_id).expect("Should exist").excess.is_zero() {
next_nodes.push_back(node_id);
}
break;
}
}
}
flows = flows
.map_arcs(|arc| ArcInfo::new(arc.head, arc.tail, arc.attributes))
.expect("By construction, this is valid");
let arcs_to_remove: Vec<(I, I)> = flows
.arc_iter()
.filter_map(|arc| {
if network.contains_arc(&arc.tail, &arc.head) {
None
} else {
Some((arc.tail, arc.head))
}
})
.collect();
flows.remove_arcs(arcs_to_remove.iter().map(|(a, b)| (a, b)));
let total_flow: T = *flows
.node(sink)
.expect("should exist")
.excess
.finite_value()
.expect("Total flow should be finite");
let flows = flows
.map_nodes(|(idx, _attrs)| (idx, ()))
.expect("By construction, this is valid");
(total_flow, flows)
}
#[inline]
fn pfp_push<I, T, NodeStore, ArcStore>(
flows: &mut Network<I, PfpNode<T>, T, NodeStore, ArcStore>,
arc: &ArcInfo<I, T>,
next_nodes: &mut VecDeque<I>,
sink: &I,
source: &I,
) where
NodeStore: NodeStorage<I, PfpNode<T>>,
ArcStore: ArcStorage<I, T>,
I: Hash + Eq + Copy,
T: Zero + Sum + Copy + Ord + Eq + AddAssign + SubAssign,
{
let node = flows.node(&arc.tail).expect("Should exist");
let delta = *node
.excess
.min(Distance::Finite(arc.attributes))
.finite_value()
.expect("Capacity is finite so this is finite");
*flows
.arc_mut(&arc.tail, &arc.head)
.expect("Arc should exist") -= delta;
if flows
.arc(&arc.tail, &arc.head)
.expect("Should exist")
.is_zero()
{
flows.remove_arc(&arc.tail, &arc.head);
}
if flows.contains_arc(&arc.head, &arc.tail) {
*flows
.arc_mut(&arc.head, &arc.tail)
.expect("Arc should exist") += delta;
} else {
let _ = flows.add_arc(ArcInfo::new(arc.head, arc.tail, delta));
}
flows.node_mut(&arc.tail).expect("Should exist").excess -= Distance::Finite(delta);
flows.node_mut(&arc.head).expect("Should exist").excess += Distance::Finite(delta);
if &arc.head != sink && &arc.head != source {
next_nodes.push_back(arc.head);
}
}
#[derive(Clone, Debug)]
struct PfpNode<T> {
pub distance_label: Distance<usize>,
pub excess: Distance<T>,
}
impl<T> PfpNode<T> {
const fn new(distance_label: Distance<usize>, excess: Distance<T>) -> Self {
Self {
distance_label,
excess,
}
}
pub const fn label(&self) -> Distance<usize> {
self.distance_label
}
}
#[cfg(test)]
mod tests {
use super::preflow_push;
use crate::Network;
#[test]
#[ignore = "Preflow Push isn't working, so we can ignore this test for now"]
fn example() {
let mut network: Network<usize, (), usize> = Network::new();
network.add_nodes((0..=5).map(|i| (i, ())));
network
.add_arcs([
(0, 1, 15),
(0, 3, 4),
(1, 2, 12),
(2, 3, 3),
(2, 5, 7),
(3, 4, 10),
(4, 1, 5),
(4, 5, 10),
])
.expect("should work");
let (max_flow_value, max_flows) = preflow_push(&network, &0, &5);
assert_eq!(max_flow_value, 14);
assert_eq!(max_flows.arc(&0, &1), Some(&10));
assert_eq!(max_flows.arc(&0, &3), Some(&4));
assert_eq!(max_flows.arc(&1, &2), Some(&10));
assert_eq!(max_flows.arc(&2, &3), Some(&3));
assert_eq!(max_flows.arc(&2, &5), Some(&7));
assert_eq!(max_flows.arc(&3, &4), Some(&7));
assert_eq!(max_flows.arc(&4, &1), None);
assert_eq!(max_flows.arc(&4, &5), Some(&7));
}
}