1use crate::base::{DiGraph, EdgeWeight, Graph, Node};
16use crate::error::{GraphError, Result};
17use std::collections::{HashMap, HashSet, VecDeque};
18
19#[derive(Debug, Clone)]
21pub struct MaxFlowResult<N: Node> {
22 pub flow_value: f64,
24 pub edge_flows: HashMap<(N, N), f64>,
26 pub source_side: HashSet<N>,
28}
29
30#[derive(Debug, Clone)]
32pub struct MinCostFlowResult<N: Node> {
33 pub flow_value: f64,
35 pub total_cost: f64,
37 pub edge_flows: HashMap<(N, N), f64>,
39}
40
41#[derive(Debug, Clone)]
43pub struct MultiCommodityFlowResult {
44 pub feasible: bool,
46 pub commodity_flows: Vec<f64>,
48 pub total_throughput: f64,
50}
51
52#[derive(Debug, Clone)]
54pub struct HopcroftKarpResult<N: Node> {
55 pub matching: Vec<(N, N)>,
57 pub size: usize,
59 pub unmatched_left: Vec<N>,
61 pub unmatched_right: Vec<N>,
63}
64
65struct ResidualGraph {
71 n: usize,
73 capacity: Vec<Vec<f64>>,
75 flow: Vec<Vec<f64>>,
77}
78
79impl ResidualGraph {
80 fn new(n: usize) -> Self {
81 Self {
82 n,
83 capacity: vec![vec![0.0; n]; n],
84 flow: vec![vec![0.0; n]; n],
85 }
86 }
87
88 fn residual_capacity(&self, u: usize, v: usize) -> f64 {
89 self.capacity[u][v] - self.flow[u][v]
90 }
91
92 fn bfs(&self, source: usize, sink: usize) -> Option<Vec<Option<usize>>> {
94 let mut parent: Vec<Option<usize>> = vec![None; self.n];
95 let mut visited = vec![false; self.n];
96 visited[source] = true;
97
98 let mut queue = VecDeque::new();
99 queue.push_back(source);
100
101 while let Some(u) = queue.pop_front() {
102 if u == sink {
103 return Some(parent);
104 }
105 for v in 0..self.n {
106 if !visited[v] && self.residual_capacity(u, v) > 1e-12 {
107 visited[v] = true;
108 parent[v] = Some(u);
109 queue.push_back(v);
110 }
111 }
112 }
113 None
114 }
115
116 fn build_level_graph(&self, source: usize) -> Vec<i64> {
118 let mut level = vec![-1i64; self.n];
119 level[source] = 0;
120 let mut queue = VecDeque::new();
121 queue.push_back(source);
122
123 while let Some(u) = queue.pop_front() {
124 for v in 0..self.n {
125 if level[v] < 0 && self.residual_capacity(u, v) > 1e-12 {
126 level[v] = level[u] + 1;
127 queue.push_back(v);
128 }
129 }
130 }
131 level
132 }
133
134 fn send_flow(
136 &mut self,
137 u: usize,
138 sink: usize,
139 pushed: f64,
140 level: &[i64],
141 iter: &mut [usize],
142 ) -> f64 {
143 if u == sink {
144 return pushed;
145 }
146 while iter[u] < self.n {
147 let v = iter[u];
148 if level[v] == level[u] + 1 && self.residual_capacity(u, v) > 1e-12 {
149 let bottleneck = pushed.min(self.residual_capacity(u, v));
150 let d = self.send_flow(v, sink, bottleneck, level, iter);
151 if d > 1e-12 {
152 self.flow[u][v] += d;
153 self.flow[v][u] -= d;
154 return d;
155 }
156 }
157 iter[u] += 1;
158 }
159 0.0
160 }
161
162 fn reachable_from(&self, source: usize) -> Vec<bool> {
164 let mut visited = vec![false; self.n];
165 let mut stack = vec![source];
166 visited[source] = true;
167
168 while let Some(u) = stack.pop() {
169 for v in 0..self.n {
170 if !visited[v] && self.residual_capacity(u, v) > 1e-12 {
171 visited[v] = true;
172 stack.push(v);
173 }
174 }
175 }
176 visited
177 }
178}
179
180fn build_node_index_maps<N, E, Ix>(graph: &DiGraph<N, E, Ix>) -> (Vec<N>, HashMap<N, usize>)
185where
186 N: Node + Clone + std::fmt::Debug,
187 E: EdgeWeight,
188 Ix: petgraph::graph::IndexType,
189{
190 let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
191 let node_to_idx: HashMap<N, usize> = nodes
192 .iter()
193 .enumerate()
194 .map(|(i, n)| (n.clone(), i))
195 .collect();
196 (nodes, node_to_idx)
197}
198
199fn build_residual_from_digraph<N, E, Ix>(
200 graph: &DiGraph<N, E, Ix>,
201 nodes: &[N],
202 node_to_idx: &HashMap<N, usize>,
203) -> ResidualGraph
204where
205 N: Node + Clone + std::fmt::Debug,
206 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
207 Ix: petgraph::graph::IndexType,
208{
209 let n = nodes.len();
210 let mut rg = ResidualGraph::new(n);
211
212 for node in nodes {
213 if let Ok(successors) = graph.successors(node) {
214 let u = node_to_idx[node];
215 for succ in &successors {
216 if let Ok(w) = graph.edge_weight(node, succ) {
217 let v = node_to_idx[succ];
218 rg.capacity[u][v] += w.into();
219 }
220 }
221 }
222 }
223 rg
224}
225
226pub fn edmonds_karp_max_flow<N, E, Ix>(
237 graph: &DiGraph<N, E, Ix>,
238 source: &N,
239 sink: &N,
240) -> Result<MaxFlowResult<N>>
241where
242 N: Node + Clone + std::fmt::Debug,
243 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
244 Ix: petgraph::graph::IndexType,
245{
246 validate_flow_input(graph, source, sink)?;
247
248 let (nodes, node_to_idx) = build_node_index_maps(graph);
249 let s = node_to_idx[source];
250 let t = node_to_idx[sink];
251 let mut rg = build_residual_from_digraph(graph, &nodes, &node_to_idx);
252
253 let mut total_flow = 0.0;
254
255 while let Some(parent) = rg.bfs(s, t) {
257 let mut path_flow = f64::INFINITY;
259 let mut v = t;
260 while v != s {
261 if let Some(u) = parent[v] {
262 path_flow = path_flow.min(rg.residual_capacity(u, v));
263 v = u;
264 } else {
265 break;
266 }
267 }
268
269 if path_flow <= 1e-12 {
270 break;
271 }
272
273 v = t;
275 while v != s {
276 if let Some(u) = parent[v] {
277 rg.flow[u][v] += path_flow;
278 rg.flow[v][u] -= path_flow;
279 v = u;
280 } else {
281 break;
282 }
283 }
284
285 total_flow += path_flow;
286 }
287
288 build_flow_result(&rg, &nodes, &node_to_idx, total_flow, s)
289}
290
291pub fn ford_fulkerson_max_flow<N, E, Ix>(
296 graph: &DiGraph<N, E, Ix>,
297 source: &N,
298 sink: &N,
299) -> Result<f64>
300where
301 N: Node + Clone + std::fmt::Debug,
302 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
303 Ix: petgraph::graph::IndexType,
304{
305 let result = edmonds_karp_max_flow(graph, source, sink)?;
306 Ok(result.flow_value)
307}
308
309pub fn dinic_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
318where
319 N: Node + Clone + std::fmt::Debug,
320 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
321 Ix: petgraph::graph::IndexType,
322{
323 let result = dinic_max_flow_full(graph, source, sink)?;
324 Ok(result.flow_value)
325}
326
327pub fn dinic_max_flow_full<N, E, Ix>(
329 graph: &DiGraph<N, E, Ix>,
330 source: &N,
331 sink: &N,
332) -> Result<MaxFlowResult<N>>
333where
334 N: Node + Clone + std::fmt::Debug,
335 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
336 Ix: petgraph::graph::IndexType,
337{
338 validate_flow_input(graph, source, sink)?;
339
340 let (nodes, node_to_idx) = build_node_index_maps(graph);
341 let s = node_to_idx[source];
342 let t = node_to_idx[sink];
343 let n = nodes.len();
344 let mut rg = build_residual_from_digraph(graph, &nodes, &node_to_idx);
345
346 let mut total_flow = 0.0;
347
348 loop {
349 let level = rg.build_level_graph(s);
350 if level[t] < 0 {
351 break; }
353
354 let mut iter = vec![0usize; n];
355 loop {
356 let f = rg.send_flow(s, t, f64::INFINITY, &level, &mut iter);
357 if f <= 1e-12 {
358 break;
359 }
360 total_flow += f;
361 }
362 }
363
364 build_flow_result(&rg, &nodes, &node_to_idx, total_flow, s)
365}
366
367pub fn push_relabel_max_flow<N, E, Ix>(
376 graph: &DiGraph<N, E, Ix>,
377 source: &N,
378 sink: &N,
379) -> Result<f64>
380where
381 N: Node + Clone + std::fmt::Debug,
382 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
383 Ix: petgraph::graph::IndexType,
384{
385 let result = push_relabel_max_flow_full(graph, source, sink)?;
386 Ok(result.flow_value)
387}
388
389pub fn push_relabel_max_flow_full<N, E, Ix>(
391 graph: &DiGraph<N, E, Ix>,
392 source: &N,
393 sink: &N,
394) -> Result<MaxFlowResult<N>>
395where
396 N: Node + Clone + std::fmt::Debug,
397 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
398 Ix: petgraph::graph::IndexType,
399{
400 validate_flow_input(graph, source, sink)?;
401
402 let (nodes, node_to_idx) = build_node_index_maps(graph);
403 let s = node_to_idx[source];
404 let t = node_to_idx[sink];
405 let n = nodes.len();
406 let mut rg = build_residual_from_digraph(graph, &nodes, &node_to_idx);
407
408 let mut height = vec![0usize; n];
410 let mut excess = vec![0.0f64; n];
411 height[s] = n;
412
413 for v in 0..n {
415 let cap = rg.residual_capacity(s, v);
416 if cap > 1e-12 {
417 rg.flow[s][v] = cap;
418 rg.flow[v][s] = -cap;
419 excess[v] += cap;
420 excess[s] -= cap;
421 }
422 }
423
424 let mut active: VecDeque<usize> = (0..n)
426 .filter(|&v| v != s && v != t && excess[v] > 1e-12)
427 .collect();
428
429 let max_iterations = n * n * 4; let mut iterations = 0;
431
432 while let Some(u) = active.pop_front() {
433 if iterations > max_iterations {
434 break;
435 }
436 iterations += 1;
437
438 if excess[u] <= 1e-12 {
439 continue;
440 }
441
442 let mut pushed = false;
444 for v in 0..n {
445 if excess[u] <= 1e-12 {
446 break;
447 }
448 if height[u] == height[v] + 1 && rg.residual_capacity(u, v) > 1e-12 {
449 let delta = excess[u].min(rg.residual_capacity(u, v));
450 rg.flow[u][v] += delta;
451 rg.flow[v][u] -= delta;
452 excess[u] -= delta;
453 excess[v] += delta;
454 if v != s && v != t && excess[v] > 1e-12 {
455 if !active.contains(&v) {
457 active.push_back(v);
458 }
459 }
460 pushed = true;
461 }
462 }
463
464 if excess[u] > 1e-12 {
466 if !pushed {
467 let mut min_height = usize::MAX;
469 for v in 0..n {
470 if rg.residual_capacity(u, v) > 1e-12 && height[v] < min_height {
471 min_height = height[v];
472 }
473 }
474 if min_height < usize::MAX {
475 height[u] = min_height + 1;
476 }
477 }
478 active.push_back(u);
479 }
480 }
481
482 let total_flow = excess[t];
483 build_flow_result(&rg, &nodes, &node_to_idx, total_flow, s)
484}
485
486pub fn minimum_cut<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Result<(f64, Vec<bool>)>
495where
496 N: Node + Clone + std::fmt::Debug,
497 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
498 Ix: petgraph::graph::IndexType,
499{
500 let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
501 let n = nodes.len();
502
503 if n < 2 {
504 return Err(GraphError::InvalidGraph(
505 "Graph must have at least 2 nodes for minimum cut".to_string(),
506 ));
507 }
508
509 let node_to_idx: HashMap<N, usize> = nodes
511 .iter()
512 .enumerate()
513 .map(|(i, n)| (n.clone(), i))
514 .collect();
515
516 let mut w = vec![vec![0.0f64; n]; n];
518 for node in &nodes {
519 if let Ok(neighbors) = graph.neighbors(node) {
520 let u = node_to_idx[node];
521 for neighbor in &neighbors {
522 if let Ok(weight) = graph.edge_weight(node, neighbor) {
523 let v = node_to_idx[neighbor];
524 w[u][v] = weight.into();
525 }
526 }
527 }
528 }
529
530 let mut merged: Vec<bool> = vec![false; n];
532 let mut groups: Vec<Vec<usize>> = (0..n).map(|i| vec![i]).collect();
533 let mut best_cut = f64::INFINITY;
534 let mut best_partition = vec![false; n];
535
536 for phase in 0..(n - 1) {
537 let mut in_a = vec![false; n];
539 let mut key = vec![0.0f64; n];
540
541 let mut start = 0;
543 for (i, &m) in merged.iter().enumerate() {
544 if !m {
545 start = i;
546 break;
547 }
548 }
549 in_a[start] = true;
550
551 for j in 0..n {
553 if !merged[j] {
554 key[j] = w[start][j];
555 }
556 }
557
558 let mut prev = start;
559 let mut last = start;
560 let active_count = n - phase;
561
562 for _ in 1..active_count {
563 let mut max_key = -1.0f64;
565 let mut max_node = 0;
566 for j in 0..n {
567 if !merged[j] && !in_a[j] && key[j] > max_key {
568 max_key = key[j];
569 max_node = j;
570 }
571 }
572
573 in_a[max_node] = true;
574 prev = last;
575 last = max_node;
576
577 for j in 0..n {
579 if !merged[j] && !in_a[j] {
580 key[j] += w[max_node][j];
581 }
582 }
583 }
584
585 let cut_value = key[last];
587 if cut_value < best_cut {
588 best_cut = cut_value;
589 best_partition = vec![false; n];
591 for &node_idx in &groups[last] {
592 best_partition[node_idx] = true;
593 }
594 }
595
596 merged[last] = true;
598 for j in 0..n {
599 w[prev][j] += w[last][j];
600 w[j][prev] += w[j][last];
601 }
602
603 let last_group = groups[last].clone();
605 groups[prev].extend(last_group);
606 }
607
608 Ok((best_cut, best_partition))
609}
610
611pub fn minimum_st_cut<N, E, Ix>(
616 graph: &DiGraph<N, E, Ix>,
617 source: &N,
618 sink: &N,
619) -> Result<(f64, HashSet<N>, HashSet<N>)>
620where
621 N: Node + Clone + std::fmt::Debug,
622 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
623 Ix: petgraph::graph::IndexType,
624{
625 let result = edmonds_karp_max_flow(graph, source, sink)?;
626 let all_nodes: HashSet<N> = graph.nodes().into_iter().cloned().collect();
627 let sink_side: HashSet<N> = all_nodes.difference(&result.source_side).cloned().collect();
628 Ok((result.flow_value, result.source_side, sink_side))
629}
630
631#[derive(Debug, Clone)]
637pub struct CostEdge {
638 pub capacity: f64,
640 pub cost: f64,
642}
643
644pub fn min_cost_max_flow(
655 n: usize,
656 edges: &[(usize, usize, f64, f64)],
657 source: usize,
658 sink: usize,
659) -> Result<MinCostFlowResult<usize>> {
660 if source >= n || sink >= n {
661 return Err(GraphError::InvalidGraph(
662 "Source or sink out of bounds".to_string(),
663 ));
664 }
665 if source == sink {
666 return Err(GraphError::InvalidGraph(
667 "Source and sink cannot be the same".to_string(),
668 ));
669 }
670
671 let mut adj: Vec<Vec<usize>> = vec![vec![]; n];
674 let mut edge_list: Vec<(usize, f64, f64, usize)> = Vec::new(); for &(u, v, cap, cost) in edges {
677 let forward_idx = edge_list.len();
678 let reverse_idx = edge_list.len() + 1;
679
680 adj[u].push(forward_idx);
681 edge_list.push((v, cap, cost, reverse_idx));
682
683 adj[v].push(reverse_idx);
684 edge_list.push((u, 0.0, -cost, forward_idx));
685 }
686
687 let mut total_flow = 0.0;
688 let mut total_cost = 0.0;
689
690 let max_outer_iterations = n * edges.len() + 1;
691 let mut outer_iter = 0;
692
693 loop {
695 if outer_iter >= max_outer_iterations {
696 break;
697 }
698 outer_iter += 1;
699
700 let mut dist = vec![f64::INFINITY; n];
702 let mut parent_edge: Vec<Option<usize>> = vec![None; n];
703 let mut in_queue = vec![false; n];
704 dist[source] = 0.0;
705
706 let mut queue = VecDeque::new();
707 queue.push_back(source);
708 in_queue[source] = true;
709
710 let max_bf_iterations = n * edge_list.len();
711 let mut bf_iter = 0;
712
713 while let Some(u) = queue.pop_front() {
714 if bf_iter > max_bf_iterations {
715 break;
716 }
717 bf_iter += 1;
718 in_queue[u] = false;
719
720 for &edge_idx in &adj[u] {
721 let (v, residual, cost, _) = edge_list[edge_idx];
722 if residual > 1e-12 && dist[u] + cost < dist[v] - 1e-12 {
723 dist[v] = dist[u] + cost;
724 parent_edge[v] = Some(edge_idx);
725 if !in_queue[v] {
726 queue.push_back(v);
727 in_queue[v] = true;
728 }
729 }
730 }
731 }
732
733 if dist[sink].is_infinite() {
734 break; }
736
737 let mut bottleneck = f64::INFINITY;
739 let mut v = sink;
740 while v != source {
741 if let Some(edge_idx) = parent_edge[v] {
742 bottleneck = bottleneck.min(edge_list[edge_idx].1);
743 let rev_idx = edge_list[edge_idx].3;
745 v = edge_list[rev_idx].0;
746 } else {
747 break;
748 }
749 }
750
751 if bottleneck <= 1e-12 {
752 break;
753 }
754
755 v = sink;
757 while v != source {
758 if let Some(edge_idx) = parent_edge[v] {
759 edge_list[edge_idx].1 -= bottleneck;
760 let rev_idx = edge_list[edge_idx].3;
761 edge_list[rev_idx].1 += bottleneck;
762 v = edge_list[rev_idx].0;
763 } else {
764 break;
765 }
766 }
767
768 total_flow += bottleneck;
769 total_cost += bottleneck * dist[sink];
770 }
771
772 let mut edge_flows = HashMap::new();
774 for (i, &(u, v, cap, cost)) in edges.iter().enumerate() {
775 let forward_idx = i * 2;
776 let flow = cap - edge_list[forward_idx].1;
777 if flow > 1e-12 {
778 let _ = cost; let _ = v; edge_flows.insert((u, edges[i].1), flow);
781 }
782 }
783
784 Ok(MinCostFlowResult {
785 flow_value: total_flow,
786 total_cost,
787 edge_flows,
788 })
789}
790
791pub fn min_cost_max_flow_graph<N, E, Ix, F>(
793 graph: &DiGraph<N, E, Ix>,
794 source: &N,
795 sink: &N,
796 cost_fn: F,
797) -> Result<(f64, f64)>
798where
799 N: Node + Clone + std::fmt::Debug,
800 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
801 Ix: petgraph::graph::IndexType,
802 F: Fn(&N, &N) -> f64,
803{
804 validate_flow_input(graph, source, sink)?;
805
806 let (nodes, node_to_idx) = build_node_index_maps(graph);
807 let s = node_to_idx[source];
808 let t = node_to_idx[sink];
809
810 let mut edges = Vec::new();
812 for node in &nodes {
813 if let Ok(successors) = graph.successors(node) {
814 let u = node_to_idx[node];
815 for succ in &successors {
816 if let Ok(w) = graph.edge_weight(node, succ) {
817 let v = node_to_idx[succ];
818 let cap: f64 = w.into();
819 let cost = cost_fn(node, succ);
820 edges.push((u, v, cap, cost));
821 }
822 }
823 }
824 }
825
826 let result = min_cost_max_flow(nodes.len(), &edges, s, t)?;
827 Ok((result.flow_value, result.total_cost))
828}
829
830pub fn multi_commodity_flow(
844 n: usize,
845 edge_caps: &[(usize, usize, f64)],
846 commodities: &[(usize, usize, f64)],
847) -> Result<MultiCommodityFlowResult> {
848 if commodities.is_empty() {
849 return Ok(MultiCommodityFlowResult {
850 feasible: true,
851 commodity_flows: vec![],
852 total_throughput: 0.0,
853 });
854 }
855
856 let mut capacity = vec![vec![0.0f64; n]; n];
858 for &(u, v, cap) in edge_caps {
859 if u < n && v < n {
860 capacity[u][v] += cap;
861 }
862 }
863
864 let num_commodities = commodities.len();
865 let mut commodity_flows = vec![0.0f64; num_commodities];
866 let mut remaining_capacity = capacity.clone();
867 let max_iterations = 100;
868
869 for _iteration in 0..max_iterations {
871 let mut any_improvement = false;
872
873 for (k, &(src, snk, demand)) in commodities.iter().enumerate() {
874 if src >= n || snk >= n || src == snk {
875 continue;
876 }
877
878 let needed = demand - commodity_flows[k];
880 if needed <= 1e-12 {
881 continue;
882 }
883
884 if let Some((path, bottleneck)) = bfs_augmenting_path(&remaining_capacity, n, src, snk)
886 {
887 let flow_to_send = bottleneck.min(needed);
888 if flow_to_send > 1e-12 {
889 for window in path.windows(2) {
891 remaining_capacity[window[0]][window[1]] -= flow_to_send;
892 }
893 commodity_flows[k] += flow_to_send;
894 any_improvement = true;
895 }
896 }
897 }
898
899 if !any_improvement {
900 break;
901 }
902 }
903
904 let total_throughput: f64 = commodity_flows.iter().sum();
905 let feasible = commodities
906 .iter()
907 .enumerate()
908 .all(|(k, &(_, _, demand))| (commodity_flows[k] - demand).abs() < 1e-6);
909
910 Ok(MultiCommodityFlowResult {
911 feasible,
912 commodity_flows,
913 total_throughput,
914 })
915}
916
917fn bfs_augmenting_path(
919 capacity: &[Vec<f64>],
920 n: usize,
921 source: usize,
922 sink: usize,
923) -> Option<(Vec<usize>, f64)> {
924 let mut parent: Vec<Option<usize>> = vec![None; n];
925 let mut visited = vec![false; n];
926 visited[source] = true;
927
928 let mut queue = VecDeque::new();
929 queue.push_back(source);
930
931 while let Some(u) = queue.pop_front() {
932 if u == sink {
933 let mut path = vec![sink];
935 let mut v = sink;
936 while v != source {
937 if let Some(p) = parent[v] {
938 path.push(p);
939 v = p;
940 } else {
941 return None;
942 }
943 }
944 path.reverse();
945
946 let mut bottleneck = f64::INFINITY;
948 for window in path.windows(2) {
949 bottleneck = bottleneck.min(capacity[window[0]][window[1]]);
950 }
951
952 return Some((path, bottleneck));
953 }
954
955 for v in 0..n {
956 if !visited[v] && capacity[u][v] > 1e-12 {
957 visited[v] = true;
958 parent[v] = Some(u);
959 queue.push_back(v);
960 }
961 }
962 }
963
964 None
965}
966
967pub fn hopcroft_karp<N, E, Ix>(
980 graph: &Graph<N, E, Ix>,
981 left_nodes: &[N],
982 right_nodes: &[N],
983) -> Result<HopcroftKarpResult<N>>
984where
985 N: Node + Clone + std::fmt::Debug,
986 E: EdgeWeight,
987 Ix: petgraph::graph::IndexType,
988{
989 let n_left = left_nodes.len();
990 let n_right = right_nodes.len();
991
992 if n_left == 0 || n_right == 0 {
993 return Ok(HopcroftKarpResult {
994 matching: vec![],
995 size: 0,
996 unmatched_left: left_nodes.to_vec(),
997 unmatched_right: right_nodes.to_vec(),
998 });
999 }
1000
1001 let left_to_idx: HashMap<N, usize> = left_nodes
1002 .iter()
1003 .enumerate()
1004 .map(|(i, n)| (n.clone(), i))
1005 .collect();
1006 let right_to_idx: HashMap<N, usize> = right_nodes
1007 .iter()
1008 .enumerate()
1009 .map(|(i, n)| (n.clone(), i))
1010 .collect();
1011
1012 let mut adj: Vec<Vec<usize>> = vec![vec![]; n_left];
1014 for (li, left_node) in left_nodes.iter().enumerate() {
1015 if let Ok(neighbors) = graph.neighbors(left_node) {
1016 for neighbor in &neighbors {
1017 if let Some(&ri) = right_to_idx.get(neighbor) {
1018 adj[li].push(ri);
1019 }
1020 }
1021 }
1022 }
1023
1024 let nil = usize::MAX;
1026 let mut match_left: Vec<usize> = vec![nil; n_left]; let mut match_right: Vec<usize> = vec![nil; n_right]; let mut dist: Vec<usize> = vec![0; n_left + 1]; let bfs_phase = |match_left: &[usize],
1032 match_right: &[usize],
1033 dist: &mut Vec<usize>,
1034 adj: &[Vec<usize>],
1035 n_left: usize|
1036 -> bool {
1037 let mut queue = VecDeque::new();
1038
1039 for u in 0..n_left {
1040 if match_left[u] == nil {
1041 dist[u] = 0;
1042 queue.push_back(u);
1043 } else {
1044 dist[u] = usize::MAX;
1045 }
1046 }
1047 dist[n_left] = usize::MAX; while let Some(u) = queue.pop_front() {
1050 if dist[u] < dist[n_left] {
1051 for &v in &adj[u] {
1052 let paired = match_right[v];
1053 let paired_dist_idx = if paired == nil { n_left } else { paired };
1054 if dist[paired_dist_idx] == usize::MAX {
1055 dist[paired_dist_idx] = dist[u] + 1;
1056 if paired_dist_idx != n_left {
1057 queue.push_back(paired_dist_idx);
1058 }
1059 }
1060 }
1061 }
1062 }
1063
1064 dist[n_left] != usize::MAX
1065 };
1066
1067 fn dfs_phase(
1069 u: usize,
1070 match_left: &mut [usize],
1071 match_right: &mut [usize],
1072 dist: &mut [usize],
1073 adj: &[Vec<usize>],
1074 n_left: usize,
1075 nil: usize,
1076 ) -> bool {
1077 if u == n_left {
1078 return true; }
1080
1081 for &v in &adj[u] {
1082 let paired = match_right[v];
1083 let paired_idx = if paired == nil { n_left } else { paired };
1084 if dist[paired_idx] == dist[u] + 1
1085 && dfs_phase(paired_idx, match_left, match_right, dist, adj, n_left, nil)
1086 {
1087 match_right[v] = u;
1088 match_left[u] = v;
1089 return true;
1090 }
1091 }
1092
1093 dist[u] = usize::MAX;
1094 false
1095 }
1096
1097 while bfs_phase(&match_left, &match_right, &mut dist, &adj, n_left) {
1099 for u in 0..n_left {
1100 if match_left[u] == nil {
1101 dfs_phase(
1102 u,
1103 &mut match_left,
1104 &mut match_right,
1105 &mut dist,
1106 &adj,
1107 n_left,
1108 nil,
1109 );
1110 }
1111 }
1112 }
1113
1114 let mut matching = Vec::new();
1116 let mut unmatched_left = Vec::new();
1117 let mut unmatched_right = Vec::new();
1118
1119 for (li, &ri) in match_left.iter().enumerate() {
1120 if ri != nil {
1121 matching.push((left_nodes[li].clone(), right_nodes[ri].clone()));
1122 } else {
1123 unmatched_left.push(left_nodes[li].clone());
1124 }
1125 }
1126
1127 for (ri, &li) in match_right.iter().enumerate() {
1128 if li == nil {
1129 unmatched_right.push(right_nodes[ri].clone());
1130 }
1131 }
1132
1133 let size = matching.len();
1134 Ok(HopcroftKarpResult {
1135 matching,
1136 size,
1137 unmatched_left,
1138 unmatched_right,
1139 })
1140}
1141
1142pub fn isap_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
1149where
1150 N: Node + Clone + std::fmt::Debug,
1151 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
1152 Ix: petgraph::graph::IndexType,
1153{
1154 dinic_max_flow(graph, source, sink)
1155}
1156
1157pub fn capacity_scaling_max_flow<N, E, Ix>(
1160 graph: &DiGraph<N, E, Ix>,
1161 source: &N,
1162 sink: &N,
1163) -> Result<f64>
1164where
1165 N: Node + Clone + std::fmt::Debug,
1166 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
1167 Ix: petgraph::graph::IndexType,
1168{
1169 let result = edmonds_karp_max_flow(graph, source, sink)?;
1170 Ok(result.flow_value)
1171}
1172
1173pub fn multi_source_multi_sink_max_flow<N, E, Ix>(
1178 graph: &DiGraph<N, E, Ix>,
1179 sources: &[N],
1180 sinks: &[N],
1181) -> Result<f64>
1182where
1183 N: Node + Clone + std::fmt::Debug,
1184 E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
1185 Ix: petgraph::graph::IndexType,
1186{
1187 if sources.is_empty() || sinks.is_empty() {
1188 return Err(GraphError::InvalidGraph(
1189 "Must have at least one source and one sink".to_string(),
1190 ));
1191 }
1192
1193 let (nodes, node_to_idx) = build_node_index_maps(graph);
1195 let n = nodes.len();
1196 let super_source = n;
1197 let super_sink = n + 1;
1198 let total_n = n + 2;
1199
1200 let mut rg = ResidualGraph::new(total_n);
1201
1202 for node in &nodes {
1204 if let Ok(successors) = graph.successors(node) {
1205 let u = node_to_idx[node];
1206 for succ in &successors {
1207 if let Ok(w) = graph.edge_weight(node, succ) {
1208 let v = node_to_idx[succ];
1209 rg.capacity[u][v] += w.into();
1210 }
1211 }
1212 }
1213 }
1214
1215 let big_cap = 1e15;
1217 for src in sources {
1218 if let Some(&idx) = node_to_idx.get(src) {
1219 rg.capacity[super_source][idx] = big_cap;
1220 }
1221 }
1222
1223 for snk in sinks {
1225 if let Some(&idx) = node_to_idx.get(snk) {
1226 rg.capacity[idx][super_sink] = big_cap;
1227 }
1228 }
1229
1230 let mut total_flow = 0.0;
1232 loop {
1233 let level = rg.build_level_graph(super_source);
1234 if level[super_sink] < 0 {
1235 break;
1236 }
1237 let mut iter = vec![0usize; total_n];
1238 loop {
1239 let f = rg.send_flow(super_source, super_sink, f64::INFINITY, &level, &mut iter);
1240 if f <= 1e-12 {
1241 break;
1242 }
1243 total_flow += f;
1244 }
1245 }
1246
1247 Ok(total_flow)
1248}
1249
1250pub fn parallel_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
1253where
1254 N: Node + Clone + Send + Sync + std::fmt::Debug,
1255 E: EdgeWeight + Into<f64> + Copy + Send + Sync + std::fmt::Debug,
1256 Ix: petgraph::graph::IndexType + Send + Sync,
1257{
1258 dinic_max_flow(graph, source, sink)
1259}
1260
1261fn validate_flow_input<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<()>
1266where
1267 N: Node + Clone + std::fmt::Debug,
1268 E: EdgeWeight,
1269 Ix: petgraph::graph::IndexType,
1270{
1271 if !graph.contains_node(source) || !graph.contains_node(sink) {
1272 return Err(GraphError::node_not_found("source or sink"));
1273 }
1274 if source == sink {
1275 return Err(GraphError::InvalidGraph(
1276 "Source and sink cannot be the same node".to_string(),
1277 ));
1278 }
1279 Ok(())
1280}
1281
1282fn build_flow_result<N: Node + Clone>(
1283 rg: &ResidualGraph,
1284 nodes: &[N],
1285 node_to_idx: &HashMap<N, usize>,
1286 total_flow: f64,
1287 source: usize,
1288) -> Result<MaxFlowResult<N>> {
1289 let reachable = rg.reachable_from(source);
1290
1291 let mut source_side = HashSet::new();
1292 for (node, &idx) in node_to_idx {
1293 if reachable[idx] {
1294 source_side.insert(node.clone());
1295 }
1296 }
1297
1298 let mut edge_flows = HashMap::new();
1299 for (ni, node_i) in nodes.iter().enumerate() {
1300 for (nj, node_j) in nodes.iter().enumerate() {
1301 let flow = rg.flow[ni][nj];
1302 if flow > 1e-12 {
1303 edge_flows.insert((node_i.clone(), node_j.clone()), flow);
1304 }
1305 }
1306 }
1307
1308 Ok(MaxFlowResult {
1309 flow_value: total_flow,
1310 edge_flows,
1311 source_side,
1312 })
1313}
1314
1315#[cfg(test)]
1320mod tests {
1321 use super::*;
1322 use crate::generators::{create_digraph, create_graph};
1323
1324 #[test]
1325 fn test_edmonds_karp_simple() -> Result<()> {
1326 let mut g = create_digraph::<&str, f64>();
1327 g.add_edge("s", "a", 10.0)?;
1328 g.add_edge("s", "b", 5.0)?;
1329 g.add_edge("a", "b", 15.0)?;
1330 g.add_edge("a", "t", 10.0)?;
1331 g.add_edge("b", "t", 10.0)?;
1332
1333 let result = edmonds_karp_max_flow(&g, &"s", &"t")?;
1334 assert!((result.flow_value - 15.0).abs() < 1e-6);
1335 Ok(())
1336 }
1337
1338 #[test]
1339 fn test_edmonds_karp_no_path() -> Result<()> {
1340 let mut g = create_digraph::<&str, f64>();
1341 g.add_edge("s", "a", 10.0)?;
1342 g.add_edge("b", "t", 10.0)?;
1343 let result = edmonds_karp_max_flow(&g, &"s", &"t")?;
1346 assert!(result.flow_value < 1e-6);
1347 Ok(())
1348 }
1349
1350 #[test]
1351 fn test_dinic_max_flow() -> Result<()> {
1352 let mut g = create_digraph::<i32, f64>();
1353 g.add_edge(0, 1, 16.0)?;
1354 g.add_edge(0, 2, 13.0)?;
1355 g.add_edge(1, 2, 10.0)?;
1356 g.add_edge(1, 3, 12.0)?;
1357 g.add_edge(2, 1, 4.0)?;
1358 g.add_edge(2, 4, 14.0)?;
1359 g.add_edge(3, 2, 9.0)?;
1360 g.add_edge(3, 5, 20.0)?;
1361 g.add_edge(4, 3, 7.0)?;
1362 g.add_edge(4, 5, 4.0)?;
1363
1364 let flow = dinic_max_flow(&g, &0, &5)?;
1365 assert!((flow - 23.0).abs() < 1e-6);
1366 Ok(())
1367 }
1368
1369 #[test]
1370 fn test_push_relabel() -> Result<()> {
1371 let mut g = create_digraph::<&str, f64>();
1372 g.add_edge("s", "a", 10.0)?;
1373 g.add_edge("s", "b", 5.0)?;
1374 g.add_edge("a", "b", 15.0)?;
1375 g.add_edge("a", "t", 10.0)?;
1376 g.add_edge("b", "t", 10.0)?;
1377
1378 let flow = push_relabel_max_flow(&g, &"s", &"t")?;
1379 assert!((flow - 15.0).abs() < 1e-6);
1380 Ok(())
1381 }
1382
1383 #[test]
1384 fn test_minimum_cut_undirected() -> Result<()> {
1385 let mut g = create_graph::<i32, f64>();
1386 g.add_edge(0, 1, 10.0)?;
1388 g.add_edge(1, 2, 10.0)?;
1389 g.add_edge(0, 2, 10.0)?;
1390 g.add_edge(3, 4, 10.0)?;
1391 g.add_edge(4, 5, 10.0)?;
1392 g.add_edge(3, 5, 10.0)?;
1393 g.add_edge(2, 3, 1.0)?; let (cut_value, partition) = minimum_cut(&g)?;
1396 assert!((cut_value - 1.0).abs() < 1e-6);
1397
1398 let true_count = partition.iter().filter(|&&b| b).count();
1400 assert!(true_count > 0 && true_count < 6);
1401 Ok(())
1402 }
1403
1404 #[test]
1405 fn test_minimum_st_cut() -> Result<()> {
1406 let mut g = create_digraph::<&str, f64>();
1407 g.add_edge("s", "a", 3.0)?;
1408 g.add_edge("s", "b", 2.0)?;
1409 g.add_edge("a", "t", 2.0)?;
1410 g.add_edge("b", "t", 3.0)?;
1411 g.add_edge("a", "b", 1.0)?;
1412
1413 let (cut_val, source_side, sink_side) = minimum_st_cut(&g, &"s", &"t")?;
1414 assert!((cut_val - 5.0).abs() < 1e-6);
1415 assert!(source_side.contains(&"s"));
1416 assert!(sink_side.contains(&"t"));
1417 Ok(())
1418 }
1419
1420 #[test]
1421 fn test_min_cost_max_flow() -> Result<()> {
1422 let edges = vec![
1424 (0, 1, 2.0, 1.0), (0, 2, 3.0, 2.0), (1, 3, 3.0, 3.0), (2, 3, 2.0, 1.0), (1, 2, 1.0, 1.0), ];
1430
1431 let result = min_cost_max_flow(4, &edges, 0, 3)?;
1432 assert!(result.flow_value > 0.0);
1433 assert!(result.total_cost > 0.0);
1434 Ok(())
1435 }
1436
1437 #[test]
1438 fn test_min_cost_max_flow_graph() -> Result<()> {
1439 let mut g = create_digraph::<i32, f64>();
1440 g.add_edge(0, 1, 4.0)?;
1441 g.add_edge(0, 2, 3.0)?;
1442 g.add_edge(1, 3, 4.0)?;
1443 g.add_edge(2, 3, 3.0)?;
1444
1445 let cost_fn = |_u: &i32, _v: &i32| 1.0;
1446 let (flow, cost) = min_cost_max_flow_graph(&g, &0, &3, cost_fn)?;
1447 assert!((flow - 7.0).abs() < 1e-6);
1448 assert!(cost > 0.0);
1449 Ok(())
1450 }
1451
1452 #[test]
1453 fn test_multi_commodity_flow() -> Result<()> {
1454 let edges = vec![(0, 1, 5.0), (1, 2, 5.0)];
1456 let commodities = vec![
1457 (0, 2, 3.0), (0, 2, 2.0), ];
1460
1461 let result = multi_commodity_flow(3, &edges, &commodities)?;
1462 assert!(result.feasible);
1463 assert!((result.total_throughput - 5.0).abs() < 1e-6);
1464 Ok(())
1465 }
1466
1467 #[test]
1468 fn test_multi_commodity_infeasible() -> Result<()> {
1469 let edges = vec![(0, 1, 3.0)];
1470 let commodities = vec![
1471 (0, 1, 2.0),
1472 (0, 1, 2.0), ];
1474
1475 let result = multi_commodity_flow(2, &edges, &commodities)?;
1476 assert!(!result.feasible);
1477 Ok(())
1478 }
1479
1480 #[test]
1481 fn test_hopcroft_karp_perfect() -> Result<()> {
1482 let mut g = create_graph::<&str, ()>();
1483 g.add_edge("a", "1", ())?;
1484 g.add_edge("a", "2", ())?;
1485 g.add_edge("b", "2", ())?;
1486 g.add_edge("b", "3", ())?;
1487 g.add_edge("c", "3", ())?;
1488 g.add_edge("c", "1", ())?;
1489
1490 let left = vec!["a", "b", "c"];
1491 let right = vec!["1", "2", "3"];
1492
1493 let result = hopcroft_karp(&g, &left, &right)?;
1494 assert_eq!(result.size, 3);
1495 assert!(result.unmatched_left.is_empty());
1496 assert!(result.unmatched_right.is_empty());
1497 Ok(())
1498 }
1499
1500 #[test]
1501 fn test_hopcroft_karp_partial() -> Result<()> {
1502 let mut g = create_graph::<i32, ()>();
1503 g.add_edge(1, 10, ())?;
1504 g.add_edge(2, 10, ())?;
1505 g.add_edge(3, 20, ())?;
1506
1507 let left = vec![1, 2, 3];
1508 let right = vec![10, 20];
1509
1510 let result = hopcroft_karp(&g, &left, &right)?;
1511 assert_eq!(result.size, 2); assert_eq!(result.unmatched_left.len(), 1);
1513 assert!(result.unmatched_right.is_empty());
1514 Ok(())
1515 }
1516
1517 #[test]
1518 fn test_hopcroft_karp_empty() -> Result<()> {
1519 let g = create_graph::<i32, ()>();
1520 let result = hopcroft_karp(&g, &[], &[])?;
1521 assert_eq!(result.size, 0);
1522 Ok(())
1523 }
1524
1525 #[test]
1526 fn test_ford_fulkerson_alias() -> Result<()> {
1527 let mut g = create_digraph::<i32, f64>();
1528 g.add_edge(0, 1, 5.0)?;
1529 g.add_edge(0, 2, 3.0)?;
1530 g.add_edge(1, 3, 4.0)?;
1531 g.add_edge(2, 3, 3.0)?;
1532
1533 let flow = ford_fulkerson_max_flow(&g, &0, &3)?;
1534 assert!((flow - 7.0).abs() < 1e-6);
1535 Ok(())
1536 }
1537
1538 #[test]
1539 fn test_multi_source_multi_sink() -> Result<()> {
1540 let mut g = create_digraph::<i32, f64>();
1541 g.add_edge(0, 2, 5.0)?; g.add_edge(1, 2, 5.0)?; g.add_edge(2, 3, 7.0)?; g.add_edge(2, 4, 3.0)?; let flow = multi_source_multi_sink_max_flow(&g, &[0, 1], &[3, 4])?;
1547 assert!(flow >= 9.0);
1548 Ok(())
1549 }
1550
1551 #[test]
1552 fn test_max_flow_invalid_input() {
1553 let mut g = create_digraph::<i32, f64>();
1554 let _ = g.add_edge(0, 1, 5.0);
1555
1556 assert!(edmonds_karp_max_flow(&g, &0, &0).is_err());
1558
1559 assert!(edmonds_karp_max_flow(&g, &0, &99).is_err());
1561 }
1562
1563 #[test]
1564 fn test_dinic_classic_example() -> Result<()> {
1565 let mut g = create_digraph::<i32, f64>();
1567 g.add_edge(0, 1, 10.0)?;
1568 g.add_edge(0, 2, 10.0)?;
1569 g.add_edge(1, 2, 2.0)?;
1570 g.add_edge(1, 3, 4.0)?;
1571 g.add_edge(1, 4, 8.0)?;
1572 g.add_edge(2, 4, 9.0)?;
1573 g.add_edge(3, 5, 10.0)?;
1574 g.add_edge(4, 3, 6.0)?;
1575 g.add_edge(4, 5, 10.0)?;
1576
1577 let flow = dinic_max_flow(&g, &0, &5)?;
1578 assert!((flow - 19.0).abs() < 1e-6);
1579 Ok(())
1580 }
1581}