Skip to main content

scirs2_graph/flow/
max_flow.rs

1//! Maximum flow algorithms
2//!
3//! This module provides three maximum flow algorithms:
4//! - **Dinic's algorithm**: O(V² E) general, O(E √V) for unit-capacity graphs
5//! - **Push-Relabel (FIFO highest-label)**: O(V² √E)
6//! - **Edmonds-Karp**: O(V E²) via BFS augmenting paths
7
8use std::collections::VecDeque;
9
10/// Internal edge representation for residual graph.
11#[derive(Debug, Clone)]
12struct FlowEdge {
13    /// Destination node
14    to: usize,
15    /// Current remaining capacity
16    cap: i64,
17    /// Index of the reverse edge in the adjacency list of `to`
18    rev: usize,
19}
20
21/// Dinic's maximum flow algorithm.
22///
23/// Builds a level graph with BFS and finds blocking flows with DFS.
24/// Time complexity: O(V² E) for general graphs, O(E √V) for unit-capacity.
25///
26/// # Example
27/// ```
28/// use scirs2_graph::flow::max_flow::DinicMaxFlow;
29///
30/// let mut d = DinicMaxFlow::new(4);
31/// d.add_edge(0, 1, 10);
32/// d.add_edge(0, 2, 10);
33/// d.add_edge(1, 3, 10);
34/// d.add_edge(2, 3, 10);
35/// d.add_edge(1, 2, 1);
36/// let flow = d.max_flow(0, 3);
37/// assert_eq!(flow, 20);
38/// ```
39#[derive(Debug, Clone)]
40pub struct DinicMaxFlow {
41    n: usize,
42    graph: Vec<Vec<FlowEdge>>,
43}
44
45impl DinicMaxFlow {
46    /// Create a new Dinic solver with `n` nodes (0-indexed).
47    pub fn new(n: usize) -> Self {
48        Self {
49            n,
50            graph: vec![vec![]; n],
51        }
52    }
53
54    /// Add a directed edge from `u` to `v` with capacity `cap`.
55    /// A reverse edge with capacity 0 is automatically added.
56    pub fn add_edge(&mut self, u: usize, v: usize, cap: i64) {
57        let rev_u = self.graph[v].len();
58        let rev_v = self.graph[u].len();
59        self.graph[u].push(FlowEdge {
60            to: v,
61            cap,
62            rev: rev_u,
63        });
64        self.graph[v].push(FlowEdge {
65            to: u,
66            cap: 0,
67            rev: rev_v,
68        });
69    }
70
71    /// Compute max flow from `source` to `sink`.
72    /// Returns 0 if source == sink or no path exists.
73    pub fn max_flow(&mut self, source: usize, sink: usize) -> i64 {
74        if source >= self.n || sink >= self.n {
75            return 0;
76        }
77        let mut total = 0i64;
78        while let Some(level) = self.bfs(source, sink) {
79            let mut iter: Vec<usize> = vec![0; self.n];
80            loop {
81                let f = self.dfs(source, sink, i64::MAX, &level, &mut iter);
82                if f == 0 {
83                    break;
84                }
85                total += f;
86            }
87        }
88        total
89    }
90
91    /// BFS to build the level graph. Returns None if sink is unreachable.
92    fn bfs(&self, source: usize, sink: usize) -> Option<Vec<i64>> {
93        let mut level = vec![-1i64; self.n];
94        level[source] = 0;
95        let mut queue = VecDeque::new();
96        queue.push_back(source);
97        while let Some(v) = queue.pop_front() {
98            for e in &self.graph[v] {
99                if e.cap > 0 && level[e.to] < 0 {
100                    level[e.to] = level[v] + 1;
101                    queue.push_back(e.to);
102                }
103            }
104        }
105        if level[sink] < 0 {
106            None
107        } else {
108            Some(level)
109        }
110    }
111
112    /// DFS blocking flow pass.
113    fn dfs(
114        &mut self,
115        v: usize,
116        sink: usize,
117        pushed: i64,
118        level: &[i64],
119        iter: &mut Vec<usize>,
120    ) -> i64 {
121        if v == sink {
122            return pushed;
123        }
124        while iter[v] < self.graph[v].len() {
125            let i = iter[v];
126            let (to, cap, rev) = {
127                let e = &self.graph[v][i];
128                (e.to, e.cap, e.rev)
129            };
130            if cap > 0 && level[v] < level[to] {
131                let d = self.dfs(to, sink, pushed.min(cap), level, iter);
132                if d > 0 {
133                    self.graph[v][i].cap -= d;
134                    self.graph[to][rev].cap += d;
135                    return d;
136                }
137            }
138            iter[v] += 1;
139        }
140        0
141    }
142
143    /// Return the current flow on each edge (forward edges only).
144    /// Each entry is `(u, v, capacity, flow)`.
145    pub fn edges(&self) -> Vec<(usize, usize, i64, i64)> {
146        let mut result = Vec::new();
147        for u in 0..self.n {
148            for e in &self.graph[u] {
149                // forward edge: cap >= 0 and the matching reverse has cap 0
150                // We detect forward edges by checking that the reverse edge's
151                // reverse index points back to us and the reverse edge has cap 0 initially.
152                // Simpler: collect all edges, original cap > 0 edges only.
153                // To avoid exposing internal bookkeeping, just return all directed edges
154                // with capacity > 0 or where flow > 0.
155                let original_cap = e.cap + self.graph[e.to][e.rev].cap;
156                if original_cap > 0 {
157                    let flow = original_cap - e.cap;
158                    result.push((u, e.to, original_cap, flow));
159                }
160            }
161        }
162        result
163    }
164}
165
166// ─────────────────────────────────────────────────────────────────────────────
167// Push-Relabel (FIFO + Highest-Label variant)
168// ─────────────────────────────────────────────────────────────────────────────
169
170/// Push-Relabel maximum flow algorithm with FIFO selection and highest-label
171/// strategy.
172///
173/// Time complexity: O(V² √E).
174///
175/// # Example
176/// ```
177/// use scirs2_graph::flow::max_flow::PushRelabelMaxFlow;
178///
179/// let mut pr = PushRelabelMaxFlow::new(4);
180/// pr.add_edge(0, 1, 10);
181/// pr.add_edge(0, 2, 10);
182/// pr.add_edge(1, 3, 10);
183/// pr.add_edge(2, 3, 10);
184/// let flow = pr.max_flow(0, 3);
185/// assert_eq!(flow, 20);
186/// ```
187#[derive(Debug, Clone)]
188pub struct PushRelabelMaxFlow {
189    n: usize,
190    graph: Vec<Vec<FlowEdge>>,
191}
192
193impl PushRelabelMaxFlow {
194    /// Create a new Push-Relabel solver with `n` nodes.
195    pub fn new(n: usize) -> Self {
196        Self {
197            n,
198            graph: vec![vec![]; n],
199        }
200    }
201
202    /// Add a directed edge from `u` to `v` with capacity `cap`.
203    pub fn add_edge(&mut self, u: usize, v: usize, cap: i64) {
204        let rev_u = self.graph[v].len();
205        let rev_v = self.graph[u].len();
206        self.graph[u].push(FlowEdge {
207            to: v,
208            cap,
209            rev: rev_u,
210        });
211        self.graph[v].push(FlowEdge {
212            to: u,
213            cap: 0,
214            rev: rev_v,
215        });
216    }
217
218    /// Compute the maximum flow from `source` to `sink`.
219    pub fn max_flow(&mut self, source: usize, sink: usize) -> i64 {
220        if source >= self.n || sink >= self.n || source == sink {
221            return 0;
222        }
223        let n = self.n;
224        let mut height = vec![0i64; n];
225        let mut excess = vec![0i64; n];
226        let mut current = vec![0usize; n];
227
228        // Initialize: saturate all edges from source
229        height[source] = n as i64;
230        for i in 0..self.graph[source].len() {
231            let (to, cap, rev) = {
232                let e = &self.graph[source][i];
233                (e.to, e.cap, e.rev)
234            };
235            if cap > 0 {
236                excess[to] += cap;
237                excess[source] -= cap;
238                self.graph[source][i].cap = 0;
239                self.graph[to][rev].cap += cap;
240            }
241        }
242
243        // Active nodes (excess > 0, not source or sink)
244        // Use a highest-label bucket queue via Vec<VecDeque<usize>>
245        let mut buckets: Vec<VecDeque<usize>> = vec![VecDeque::new(); 2 * n + 1];
246        let mut in_queue = vec![false; n];
247        for v in 0..n {
248            if v != source && v != sink && excess[v] > 0 {
249                let h = height[v] as usize;
250                buckets[h].push_back(v);
251                in_queue[v] = true;
252            }
253        }
254
255        let mut highest = n - 1;
256
257        loop {
258            // Find highest active node
259            while highest > 0 && buckets[highest].is_empty() {
260                if highest == 0 {
261                    break;
262                }
263                highest -= 1;
264            }
265            if buckets[highest].is_empty() {
266                break;
267            }
268            let v = match buckets[highest].front().copied() {
269                Some(x) => x,
270                None => break,
271            };
272
273            // Discharge v
274            while excess[v] > 0 {
275                if current[v] == self.graph[v].len() {
276                    // Relabel
277                    let min_h = self.graph[v]
278                        .iter()
279                        .filter(|e| e.cap > 0)
280                        .map(|e| height[e.to])
281                        .min()
282                        .unwrap_or(2 * n as i64);
283                    height[v] = min_h + 1;
284                    current[v] = 0;
285                    // Move to new bucket
286                    let old_h = highest;
287                    let _ = buckets[old_h].pop_front();
288                    in_queue[v] = false;
289                    let new_h = height[v] as usize;
290                    if new_h < 2 * n {
291                        buckets[new_h].push_front(v);
292                        in_queue[v] = true;
293                        if new_h > highest {
294                            highest = new_h;
295                        }
296                    }
297                    break;
298                }
299                let i = current[v];
300                let (to, cap, rev) = {
301                    let e = &self.graph[v][i];
302                    (e.to, e.cap, e.rev)
303                };
304                if cap > 0 && height[v] == height[to] + 1 {
305                    let pushed = excess[v].min(cap);
306                    excess[v] -= pushed;
307                    excess[to] += pushed;
308                    self.graph[v][i].cap -= pushed;
309                    self.graph[to][rev].cap += pushed;
310
311                    if to != source && to != sink && !in_queue[to] && excess[to] > 0 {
312                        let h = height[to] as usize;
313                        if h < 2 * n {
314                            buckets[h].push_back(to);
315                            in_queue[to] = true;
316                            if h > highest {
317                                highest = h;
318                            }
319                        }
320                    }
321                } else {
322                    current[v] += 1;
323                }
324            }
325
326            // If v was fully discharged, remove from bucket
327            if excess[v] == 0 {
328                if let Some(&front) = buckets[highest].front() {
329                    if front == v {
330                        buckets[highest].pop_front();
331                        in_queue[v] = false;
332                    }
333                }
334            }
335        }
336
337        excess[sink].max(0)
338    }
339}
340
341// ─────────────────────────────────────────────────────────────────────────────
342// Edmonds-Karp (BFS augmenting paths)
343// ─────────────────────────────────────────────────────────────────────────────
344
345/// Edmonds-Karp maximum flow algorithm.
346///
347/// Uses BFS to find shortest augmenting paths (Ford-Fulkerson with BFS).
348/// Time complexity: O(V E²).
349///
350/// # Example
351/// ```
352/// use scirs2_graph::flow::max_flow::EdmondsKarp;
353///
354/// let mut ek = EdmondsKarp::new(4);
355/// ek.add_edge(0, 1, 10);
356/// ek.add_edge(0, 2, 10);
357/// ek.add_edge(1, 3, 10);
358/// ek.add_edge(2, 3, 10);
359/// let flow = ek.max_flow(0, 3);
360/// assert_eq!(flow, 20);
361/// ```
362#[derive(Debug, Clone)]
363pub struct EdmondsKarp {
364    n: usize,
365    graph: Vec<Vec<FlowEdge>>,
366}
367
368impl EdmondsKarp {
369    /// Create a new Edmonds-Karp solver with `n` nodes.
370    pub fn new(n: usize) -> Self {
371        Self {
372            n,
373            graph: vec![vec![]; n],
374        }
375    }
376
377    /// Add a directed edge from `u` to `v` with capacity `cap`.
378    pub fn add_edge(&mut self, u: usize, v: usize, cap: i64) {
379        let rev_u = self.graph[v].len();
380        let rev_v = self.graph[u].len();
381        self.graph[u].push(FlowEdge {
382            to: v,
383            cap,
384            rev: rev_u,
385        });
386        self.graph[v].push(FlowEdge {
387            to: u,
388            cap: 0,
389            rev: rev_v,
390        });
391    }
392
393    /// Compute maximum flow from `source` to `sink`.
394    pub fn max_flow(&mut self, source: usize, sink: usize) -> i64 {
395        if source >= self.n || sink >= self.n {
396            return 0;
397        }
398        let mut total = 0i64;
399        loop {
400            // BFS to find shortest augmenting path
401            let mut parent: Vec<Option<(usize, usize)>> = vec![None; self.n];
402            parent[source] = Some((source, 0));
403            let mut queue = VecDeque::new();
404            queue.push_back(source);
405            'bfs: while let Some(v) = queue.pop_front() {
406                for (i, e) in self.graph[v].iter().enumerate() {
407                    if e.cap > 0 && parent[e.to].is_none() {
408                        parent[e.to] = Some((v, i));
409                        if e.to == sink {
410                            break 'bfs;
411                        }
412                        queue.push_back(e.to);
413                    }
414                }
415            }
416            if parent[sink].is_none() {
417                break;
418            }
419            // Find bottleneck
420            let mut bottleneck = i64::MAX;
421            let mut node = sink;
422            while node != source {
423                let (prev, ei) = match parent[node] {
424                    Some(p) => p,
425                    None => break,
426                };
427                bottleneck = bottleneck.min(self.graph[prev][ei].cap);
428                node = prev;
429            }
430            // Augment
431            let mut node = sink;
432            while node != source {
433                let (prev, ei) = match parent[node] {
434                    Some(p) => p,
435                    None => break,
436                };
437                let rev = self.graph[prev][ei].rev;
438                self.graph[prev][ei].cap -= bottleneck;
439                self.graph[node][rev].cap += bottleneck;
440                node = prev;
441            }
442            total += bottleneck;
443        }
444        total
445    }
446}
447
448#[cfg(test)]
449mod tests {
450    use super::*;
451
452    fn simple_graph() -> (usize, Vec<(usize, usize, i64)>) {
453        // 4-node graph: 0→1 (10), 0→2 (10), 1→3 (10), 2→3 (10), 1→2 (1)
454        (
455            4,
456            vec![(0, 1, 10), (0, 2, 10), (1, 3, 10), (2, 3, 10), (1, 2, 1)],
457        )
458    }
459
460    #[test]
461    fn test_dinic_simple() {
462        let (n, edges) = simple_graph();
463        let mut d = DinicMaxFlow::new(n);
464        for (u, v, c) in &edges {
465            d.add_edge(*u, *v, *c);
466        }
467        assert_eq!(d.max_flow(0, 3), 20);
468    }
469
470    #[test]
471    fn test_push_relabel_simple() {
472        let (n, edges) = simple_graph();
473        let mut pr = PushRelabelMaxFlow::new(n);
474        for (u, v, c) in &edges {
475            pr.add_edge(*u, *v, *c);
476        }
477        assert_eq!(pr.max_flow(0, 3), 20);
478    }
479
480    #[test]
481    fn test_edmonds_karp_simple() {
482        let (n, edges) = simple_graph();
483        let mut ek = EdmondsKarp::new(n);
484        for (u, v, c) in &edges {
485            ek.add_edge(*u, *v, *c);
486        }
487        assert_eq!(ek.max_flow(0, 3), 20);
488    }
489
490    #[test]
491    fn test_dinic_no_path() {
492        let mut d = DinicMaxFlow::new(3);
493        d.add_edge(0, 1, 5);
494        // no edge to node 2
495        assert_eq!(d.max_flow(0, 2), 0);
496    }
497
498    #[test]
499    fn test_edmonds_karp_bottleneck() {
500        let mut ek = EdmondsKarp::new(3);
501        ek.add_edge(0, 1, 100);
502        ek.add_edge(1, 2, 1);
503        assert_eq!(ek.max_flow(0, 2), 1);
504    }
505
506    #[test]
507    fn test_dinic_cycle() {
508        // Graph with a cycle
509        let mut d = DinicMaxFlow::new(4);
510        d.add_edge(0, 1, 5);
511        d.add_edge(1, 2, 3);
512        d.add_edge(2, 1, 2);
513        d.add_edge(1, 3, 4);
514        d.add_edge(2, 3, 3);
515        // max flow 0→3: path 0→1→3 gives 4, path 0→1→2→3 gives 1 = total 5
516        assert_eq!(d.max_flow(0, 3), 5);
517    }
518
519    #[test]
520    fn test_push_relabel_larger() {
521        // CLRS example: 6 nodes
522        let mut pr = PushRelabelMaxFlow::new(6);
523        pr.add_edge(0, 1, 16);
524        pr.add_edge(0, 2, 13);
525        pr.add_edge(1, 2, 10);
526        pr.add_edge(1, 3, 12);
527        pr.add_edge(2, 1, 4);
528        pr.add_edge(2, 4, 14);
529        pr.add_edge(3, 2, 9);
530        pr.add_edge(3, 5, 20);
531        pr.add_edge(4, 3, 7);
532        pr.add_edge(4, 5, 4);
533        assert_eq!(pr.max_flow(0, 5), 23);
534    }
535
536    #[test]
537    fn test_dinic_clrs_example() {
538        let mut d = DinicMaxFlow::new(6);
539        d.add_edge(0, 1, 16);
540        d.add_edge(0, 2, 13);
541        d.add_edge(1, 2, 10);
542        d.add_edge(1, 3, 12);
543        d.add_edge(2, 1, 4);
544        d.add_edge(2, 4, 14);
545        d.add_edge(3, 2, 9);
546        d.add_edge(3, 5, 20);
547        d.add_edge(4, 3, 7);
548        d.add_edge(4, 5, 4);
549        assert_eq!(d.max_flow(0, 5), 23);
550    }
551
552    #[test]
553    fn test_zero_capacity() {
554        let mut d = DinicMaxFlow::new(2);
555        d.add_edge(0, 1, 0);
556        assert_eq!(d.max_flow(0, 1), 0);
557    }
558
559    #[test]
560    fn test_single_edge() {
561        let mut d = DinicMaxFlow::new(2);
562        d.add_edge(0, 1, 42);
563        assert_eq!(d.max_flow(0, 1), 42);
564    }
565
566    #[test]
567    fn test_all_three_agree() {
568        // Use same topology, confirm all three give same answer
569        let edges = vec![
570            (0usize, 1usize, 7i64),
571            (0, 2, 4),
572            (1, 3, 3),
573            (1, 4, 5),
574            (2, 4, 4),
575            (3, 5, 5),
576            (4, 5, 6),
577        ];
578        let n = 6;
579        let mut d = DinicMaxFlow::new(n);
580        let mut pr = PushRelabelMaxFlow::new(n);
581        let mut ek = EdmondsKarp::new(n);
582        for &(u, v, c) in &edges {
583            d.add_edge(u, v, c);
584            pr.add_edge(u, v, c);
585            ek.add_edge(u, v, c);
586        }
587        let fd = d.max_flow(0, 5);
588        let fpr = pr.max_flow(0, 5);
589        let fek = ek.max_flow(0, 5);
590        assert_eq!(fd, fpr, "Dinic vs PushRelabel mismatch");
591        assert_eq!(fd, fek, "Dinic vs EdmondsKarp mismatch");
592    }
593}