#![allow(dead_code)]
pub struct FlowGraph {
pub n: usize,
pub cap: Vec<Vec<f32>>,
}
impl FlowGraph {
pub fn new(n: usize) -> Self {
FlowGraph {
n,
cap: vec![vec![0.0; n]; n],
}
}
}
pub fn new_flow_graph(n: usize) -> FlowGraph {
FlowGraph::new(n)
}
pub fn fg_add_edge(g: &mut FlowGraph, u: usize, v: usize, c: f32) {
if u < g.n && v < g.n {
g.cap[u][v] += c;
}
}
pub fn fg_node_count(g: &FlowGraph) -> usize {
g.n
}
#[allow(clippy::needless_range_loop)]
pub fn max_flow(g: &FlowGraph, src: usize, sink: usize) -> f32 {
if src >= g.n || sink >= g.n || src == sink {
return 0.0;
}
let n = g.n;
let mut residual = g.cap.clone();
let mut total = 0.0f32;
loop {
let mut prev = vec![usize::MAX; n];
let mut visited = vec![false; n];
let mut queue = std::collections::VecDeque::new();
visited[src] = true;
queue.push_back(src);
while let Some(u) = queue.pop_front() {
if u == sink {
break;
}
for v in 0..n {
if !visited[v] && residual[u][v] > 1e-9 {
visited[v] = true;
prev[v] = u;
queue.push_back(v);
}
}
}
if !visited[sink] {
break;
}
let mut flow = f32::INFINITY;
let mut cur = sink;
while cur != src {
let p = prev[cur];
flow = flow.min(residual[p][cur]);
cur = p;
}
cur = sink;
while cur != src {
let p = prev[cur];
residual[p][cur] -= flow;
residual[cur][p] += flow;
cur = p;
}
total += flow;
}
total
}
#[allow(clippy::needless_range_loop)]
pub fn fg_has_augmenting_path(g: &FlowGraph, src: usize, sink: usize) -> bool {
let small = FlowGraph {
n: g.n,
cap: g.cap.clone(),
};
let _ = small;
let mut visited = vec![false; g.n];
let mut queue = std::collections::VecDeque::new();
if src < g.n {
visited[src] = true;
queue.push_back(src);
}
while let Some(u) = queue.pop_front() {
if u == sink {
return true;
}
for v in 0..g.n {
if !visited[v] && g.cap[u][v] > 1e-9 {
visited[v] = true;
queue.push_back(v);
}
}
}
false
}
pub fn fg_total_capacity_from(g: &FlowGraph, src: usize) -> f32 {
if src >= g.n {
return 0.0;
}
g.cap[src].iter().sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_flow() {
let mut g = new_flow_graph(4);
fg_add_edge(&mut g, 0, 1, 3.0);
fg_add_edge(&mut g, 0, 2, 2.0);
fg_add_edge(&mut g, 1, 3, 3.0);
fg_add_edge(&mut g, 2, 3, 2.0);
assert!((max_flow(&g, 0, 3) - 5.0).abs() < 1e-5);
}
#[test]
fn test_no_path_returns_zero() {
let g = new_flow_graph(3);
assert_eq!(max_flow(&g, 0, 2), 0.0);
}
#[test]
fn test_bottleneck_edge() {
let mut g = new_flow_graph(3);
fg_add_edge(&mut g, 0, 1, 100.0);
fg_add_edge(&mut g, 1, 2, 1.0);
assert!((max_flow(&g, 0, 2) - 1.0).abs() < 1e-5);
}
#[test]
fn test_parallel_paths() {
let mut g = new_flow_graph(4);
fg_add_edge(&mut g, 0, 1, 5.0);
fg_add_edge(&mut g, 0, 2, 5.0);
fg_add_edge(&mut g, 1, 3, 5.0);
fg_add_edge(&mut g, 2, 3, 5.0);
assert!((max_flow(&g, 0, 3) - 10.0).abs() < 1e-5);
}
#[test]
fn test_node_count() {
let g = new_flow_graph(6);
assert_eq!(fg_node_count(&g), 6);
}
#[test]
fn test_capacity_from() {
let mut g = new_flow_graph(3);
fg_add_edge(&mut g, 0, 1, 3.0);
fg_add_edge(&mut g, 0, 2, 4.0);
assert!((fg_total_capacity_from(&g, 0) - 7.0).abs() < 1e-5);
}
#[test]
fn test_src_equals_sink() {
let g = new_flow_graph(3);
let _ = max_flow(&g, 1, 1);
}
#[test]
fn test_diamond_graph() {
let mut g = new_flow_graph(6);
fg_add_edge(&mut g, 0, 1, 10.0);
fg_add_edge(&mut g, 0, 2, 10.0);
fg_add_edge(&mut g, 1, 3, 10.0);
fg_add_edge(&mut g, 2, 4, 10.0);
fg_add_edge(&mut g, 3, 5, 10.0);
fg_add_edge(&mut g, 4, 5, 10.0);
fg_add_edge(&mut g, 1, 4, 5.0);
fg_add_edge(&mut g, 2, 3, 5.0);
assert!(max_flow(&g, 0, 5) >= 20.0 - 1e-3);
}
}