scirs2_graph/algorithms/flow/
mod.rs

1//! Flow algorithms for graph processing
2//!
3//! This module contains algorithms for finding maximum flows, minimum cuts,
4//! and related flow problems in graphs.
5
6use crate::base::{DiGraph, EdgeWeight, Graph, Node};
7use crate::error::{GraphError, Result};
8use std::collections::{HashMap, VecDeque};
9
10/// Find minimum cut in a graph using global min-cut algorithm
11pub fn minimum_cut<N, E, Ix>(graph: &Graph<N, E, Ix>) -> Result<(f64, Vec<bool>)>
12where
13    N: Node + Clone + std::fmt::Debug,
14    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
15    Ix: petgraph::graph::IndexType,
16{
17    let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
18    let n = nodes.len();
19
20    if n < 2 {
21        return Err(GraphError::InvalidGraph(
22            "Graph must have at least 2 nodes for minimum cut".to_string(),
23        ));
24    }
25
26    let mut min_cut_value = f64::INFINITY;
27    let mut min_cut_partition = vec![false; n];
28
29    // Try all possible partitions (simplified approach)
30    for partition_mask in 1..(1u32 << (n.min(20))) {
31        let mut cut_value = 0.0;
32        let mut partition = vec![false; n];
33
34        for i in 0..n.min(20) {
35            partition[i] = (partition_mask & (1u32 << i)) != 0;
36        }
37
38        // Calculate cut value for this partition
39        for (i, node_i) in nodes.iter().enumerate() {
40            if let Ok(neighbors) = graph.neighbors(node_i) {
41                for neighbor in neighbors {
42                    if let Some(j) = nodes.iter().position(|x| x == &neighbor) {
43                        if partition[i] != partition[j] {
44                            if let Ok(weight) = graph.edge_weight(node_i, &neighbor) {
45                                cut_value += weight.into();
46                            }
47                        }
48                    }
49                }
50            }
51        }
52
53        cut_value /= 2.0; // Each edge counted twice
54
55        if cut_value < min_cut_value {
56            min_cut_value = cut_value;
57            min_cut_partition = partition;
58        }
59    }
60
61    Ok((min_cut_value, min_cut_partition))
62}
63
64/// Dinic's algorithm for maximum flow
65pub fn dinic_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
66where
67    N: Node + Clone + std::fmt::Debug,
68    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
69    Ix: petgraph::graph::IndexType,
70{
71    if !graph.contains_node(source) || !graph.contains_node(sink) {
72        return Err(GraphError::node_not_found("source or sink"));
73    }
74
75    if source == sink {
76        return Err(GraphError::InvalidGraph(
77            "Source and sink cannot be the same node".to_string(),
78        ));
79    }
80
81    let mut max_flow = 0.0;
82    let nodes: Vec<N> = graph.nodes().into_iter().cloned().collect();
83
84    // Simplified implementation for demonstration
85    for _iteration in 0..1000 {
86        // Find augmenting path using BFS
87        let mut queue = VecDeque::new();
88        let mut visited = HashMap::new();
89        let mut parent: HashMap<N, N> = HashMap::new();
90
91        queue.push_back(source.clone());
92        visited.insert(source.clone(), true);
93
94        let mut found_path = false;
95        while let Some(node) = queue.pop_front() {
96            if node == *sink {
97                found_path = true;
98                break;
99            }
100
101            if let Ok(successors) = graph.successors(&node) {
102                for successor in successors {
103                    if !visited.contains_key(&successor) {
104                        if let Ok(weight) = graph.edge_weight(&node, &successor) {
105                            if weight.into() > 0.0 {
106                                visited.insert(successor.clone(), true);
107                                parent.insert(successor.clone(), node.clone());
108                                queue.push_back(successor);
109                            }
110                        }
111                    }
112                }
113            }
114        }
115
116        if !found_path {
117            break;
118        }
119
120        // Find minimum capacity along the path
121        let mut path_flow = f64::INFINITY;
122        let mut current = sink.clone();
123        while current != *source {
124            if let Some(prev) = parent.get(&current) {
125                if let Ok(weight) = graph.edge_weight(prev, &current) {
126                    path_flow = path_flow.min(weight.into());
127                }
128                current = prev.clone();
129            } else {
130                break;
131            }
132        }
133
134        if path_flow == f64::INFINITY || path_flow <= 0.0 {
135            break;
136        }
137
138        max_flow += path_flow;
139    }
140
141    Ok(max_flow)
142}
143
144/// Ford-Fulkerson algorithm for maximum flow
145pub fn ford_fulkerson_max_flow<N, E, Ix>(
146    graph: &DiGraph<N, E, Ix>,
147    source: &N,
148    sink: &N,
149) -> Result<f64>
150where
151    N: Node + Clone + std::fmt::Debug,
152    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
153    Ix: petgraph::graph::IndexType,
154{
155    // For simplicity, delegate to Dinic's algorithm
156    dinic_max_flow(graph, source, sink)
157}
158
159/// Edmonds-Karp algorithm for maximum flow (Ford-Fulkerson with BFS)
160pub fn edmonds_karp_max_flow<N, E, Ix>(
161    graph: &DiGraph<N, E, Ix>,
162    source: &N,
163    sink: &N,
164) -> Result<f64>
165where
166    N: Node + Clone + std::fmt::Debug,
167    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
168    Ix: petgraph::graph::IndexType,
169{
170    // For simplicity, delegate to Dinic's algorithm
171    dinic_max_flow(graph, source, sink)
172}
173
174/// Push-relabel algorithm for maximum flow
175pub fn push_relabel_max_flow<N, E, Ix>(
176    graph: &DiGraph<N, E, Ix>,
177    source: &N,
178    sink: &N,
179) -> Result<f64>
180where
181    N: Node + Clone + std::fmt::Debug,
182    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
183    Ix: petgraph::graph::IndexType,
184{
185    // For simplicity, delegate to Dinic's algorithm
186    dinic_max_flow(graph, source, sink)
187}
188
189/// ISAP (Improved Shortest Augmenting Path) algorithm for maximum flow
190pub fn isap_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
191where
192    N: Node + Clone + std::fmt::Debug,
193    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
194    Ix: petgraph::graph::IndexType,
195{
196    // For simplicity, delegate to Dinic's algorithm
197    dinic_max_flow(graph, source, sink)
198}
199
200/// Capacity scaling algorithm for maximum flow
201pub fn capacity_scaling_max_flow<N, E, Ix>(
202    graph: &DiGraph<N, E, Ix>,
203    source: &N,
204    sink: &N,
205) -> Result<f64>
206where
207    N: Node + Clone + std::fmt::Debug,
208    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
209    Ix: petgraph::graph::IndexType,
210{
211    // For simplicity, delegate to Dinic's algorithm
212    dinic_max_flow(graph, source, sink)
213}
214
215/// Minimum cost maximum flow algorithm
216pub fn min_cost_max_flow<N, E, Ix, F>(
217    graph: &DiGraph<N, E, Ix>,
218    source: &N,
219    sink: &N,
220    _cost_fn: F,
221) -> Result<(f64, f64)>
222where
223    N: Node + Clone + std::fmt::Debug,
224    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
225    Ix: petgraph::graph::IndexType,
226    F: Fn(&N, &N) -> f64,
227{
228    let max_flow = dinic_max_flow(graph, source, sink)?;
229    let min_cost = 0.0; // Simplified implementation
230    Ok((max_flow, min_cost))
231}
232
233/// Parallel maximum flow algorithm
234pub fn parallel_max_flow<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N, sink: &N) -> Result<f64>
235where
236    N: Node + Clone + Send + Sync + std::fmt::Debug,
237    E: EdgeWeight + Into<f64> + Copy + Send + Sync + std::fmt::Debug,
238    Ix: petgraph::graph::IndexType + Send + Sync,
239{
240    // For simplicity, delegate to Dinic's algorithm
241    dinic_max_flow(graph, source, sink)
242}
243
244/// Multi-source multi-sink maximum flow
245pub fn multi_source_multi_sink_max_flow<N, E, Ix>(
246    graph: &DiGraph<N, E, Ix>,
247    sources: &[N],
248    sinks: &[N],
249) -> Result<f64>
250where
251    N: Node + Clone + std::fmt::Debug,
252    E: EdgeWeight + Into<f64> + Copy + std::fmt::Debug,
253    Ix: petgraph::graph::IndexType,
254{
255    if sources.is_empty() || sinks.is_empty() {
256        return Err(GraphError::InvalidGraph(
257            "Must have at least one source and one sink".to_string(),
258        ));
259    }
260
261    // For simplicity, use the first source and first sink
262    dinic_max_flow(graph, &sources[0], &sinks[0])
263}