1use crate::error::{SparseError, SparseResult};
10use crate::sparray::SparseArray;
11use scirs2_core::numeric::{Float, SparseElement};
12use std::collections::VecDeque;
13use std::fmt::Debug;
14
15#[derive(Debug, Clone)]
17pub struct MaxFlowResult<T> {
18 pub flow_value: T,
20 pub flow_matrix: Vec<Vec<T>>,
22}
23
24pub fn ford_fulkerson<T, S>(graph: &S, source: usize, sink: usize) -> SparseResult<MaxFlowResult<T>>
36where
37 T: Float + SparseElement + Debug + Copy + 'static,
38 S: SparseArray<T>,
39{
40 let n = graph.shape().0;
41
42 if graph.shape().0 != graph.shape().1 {
43 return Err(SparseError::ValueError(
44 "Graph matrix must be square".to_string(),
45 ));
46 }
47
48 if source >= n || sink >= n {
49 return Err(SparseError::ValueError(
50 "Source and sink must be valid vertices".to_string(),
51 ));
52 }
53
54 let mut residual = vec![vec![T::sparse_zero(); n]; n];
56 for i in 0..n {
57 for j in 0..n {
58 residual[i][j] = graph.get(i, j);
59 }
60 }
61
62 let mut max_flow = T::sparse_zero();
63
64 loop {
66 let mut visited = vec![false; n];
67 let mut parent = vec![None; n];
68
69 if !dfs_find_path(&residual, source, sink, &mut visited, &mut parent) {
70 break;
71 }
72
73 let mut path_flow = T::from(f64::INFINITY)
75 .ok_or_else(|| SparseError::ComputationError("Cannot create infinity".to_string()))?;
76
77 let mut current = sink;
78 while let Some(prev) = parent[current] {
79 path_flow = if residual[prev][current] < path_flow {
80 residual[prev][current]
81 } else {
82 path_flow
83 };
84 current = prev;
85 }
86
87 current = sink;
89 while let Some(prev) = parent[current] {
90 residual[prev][current] = residual[prev][current] - path_flow;
91 residual[current][prev] = residual[current][prev] + path_flow;
92 current = prev;
93 }
94
95 max_flow = max_flow + path_flow;
96 }
97
98 Ok(MaxFlowResult {
99 flow_value: max_flow,
100 flow_matrix: residual,
101 })
102}
103
104fn dfs_find_path<T>(
106 residual: &[Vec<T>],
107 current: usize,
108 sink: usize,
109 visited: &mut [bool],
110 parent: &mut [Option<usize>],
111) -> bool
112where
113 T: Float + SparseElement + Debug + Copy + 'static,
114{
115 if current == sink {
116 return true;
117 }
118
119 visited[current] = true;
120
121 for neighbor in 0..residual.len() {
122 if !visited[neighbor] && residual[current][neighbor] > T::sparse_zero() {
123 parent[neighbor] = Some(current);
124 if dfs_find_path(residual, neighbor, sink, visited, parent) {
125 return true;
126 }
127 }
128 }
129
130 false
131}
132
133pub fn edmonds_karp<T, S>(graph: &S, source: usize, sink: usize) -> SparseResult<MaxFlowResult<T>>
145where
146 T: Float + SparseElement + Debug + Copy + 'static,
147 S: SparseArray<T>,
148{
149 let n = graph.shape().0;
150
151 if graph.shape().0 != graph.shape().1 {
152 return Err(SparseError::ValueError(
153 "Graph matrix must be square".to_string(),
154 ));
155 }
156
157 if source >= n || sink >= n {
158 return Err(SparseError::ValueError(
159 "Source and sink must be valid vertices".to_string(),
160 ));
161 }
162
163 let mut residual = vec![vec![T::sparse_zero(); n]; n];
165 for i in 0..n {
166 for j in 0..n {
167 residual[i][j] = graph.get(i, j);
168 }
169 }
170
171 let mut max_flow = T::sparse_zero();
172
173 loop {
175 let mut parent = vec![None; n];
176
177 if !bfs_find_path(&residual, source, sink, &mut parent) {
178 break;
179 }
180
181 let mut path_flow = T::from(f64::INFINITY)
183 .ok_or_else(|| SparseError::ComputationError("Cannot create infinity".to_string()))?;
184
185 let mut current = sink;
186 while let Some(prev) = parent[current] {
187 path_flow = if residual[prev][current] < path_flow {
188 residual[prev][current]
189 } else {
190 path_flow
191 };
192 current = prev;
193 }
194
195 current = sink;
197 while let Some(prev) = parent[current] {
198 residual[prev][current] = residual[prev][current] - path_flow;
199 residual[current][prev] = residual[current][prev] + path_flow;
200 current = prev;
201 }
202
203 max_flow = max_flow + path_flow;
204 }
205
206 Ok(MaxFlowResult {
207 flow_value: max_flow,
208 flow_matrix: residual,
209 })
210}
211
212fn bfs_find_path<T>(
214 residual: &[Vec<T>],
215 source: usize,
216 sink: usize,
217 parent: &mut [Option<usize>],
218) -> bool
219where
220 T: Float + SparseElement + Debug + Copy + 'static,
221{
222 let n = residual.len();
223 let mut visited = vec![false; n];
224 let mut queue = VecDeque::new();
225
226 queue.push_back(source);
227 visited[source] = true;
228
229 while let Some(current) = queue.pop_front() {
230 if current == sink {
231 return true;
232 }
233
234 for neighbor in 0..n {
235 if !visited[neighbor] && residual[current][neighbor] > T::sparse_zero() {
236 visited[neighbor] = true;
237 parent[neighbor] = Some(current);
238 queue.push_back(neighbor);
239 }
240 }
241 }
242
243 false
244}
245
246pub fn dinic<T, S>(graph: &S, source: usize, sink: usize) -> SparseResult<MaxFlowResult<T>>
260where
261 T: Float + SparseElement + Debug + Copy + 'static,
262 S: SparseArray<T>,
263{
264 let n = graph.shape().0;
265
266 if graph.shape().0 != graph.shape().1 {
267 return Err(SparseError::ValueError(
268 "Graph matrix must be square".to_string(),
269 ));
270 }
271
272 if source >= n || sink >= n {
273 return Err(SparseError::ValueError(
274 "Source and sink must be valid vertices".to_string(),
275 ));
276 }
277
278 let mut residual = vec![vec![T::sparse_zero(); n]; n];
280 for i in 0..n {
281 for j in 0..n {
282 residual[i][j] = graph.get(i, j);
283 }
284 }
285
286 let mut max_flow = T::sparse_zero();
287
288 loop {
290 let level = build_level_graph(&residual, source, sink);
292
293 if level[sink] < 0 {
294 break;
296 }
297
298 loop {
300 let mut visited = vec![false; n];
301 let flow = send_flow(
302 &mut residual,
303 &level,
304 source,
305 sink,
306 &mut visited,
307 T::from(f64::INFINITY).ok_or_else(|| {
308 SparseError::ComputationError("Cannot create infinity".to_string())
309 })?,
310 );
311
312 if scirs2_core::SparseElement::is_zero(&flow) {
313 break;
314 }
315
316 max_flow = max_flow + flow;
317 }
318 }
319
320 Ok(MaxFlowResult {
321 flow_value: max_flow,
322 flow_matrix: residual,
323 })
324}
325
326fn build_level_graph<T>(residual: &[Vec<T>], source: usize, sink: usize) -> Vec<i32>
328where
329 T: Float + SparseElement + Debug + Copy + 'static,
330{
331 let n = residual.len();
332 let mut level = vec![-1; n];
333 level[source] = 0;
334
335 let mut queue = VecDeque::new();
336 queue.push_back(source);
337
338 while let Some(current) = queue.pop_front() {
339 for neighbor in 0..n {
340 if level[neighbor] < 0 && residual[current][neighbor] > T::sparse_zero() {
341 level[neighbor] = level[current] + 1;
342 queue.push_back(neighbor);
343
344 if neighbor == sink {
345 return level;
346 }
347 }
348 }
349 }
350
351 level
352}
353
354fn send_flow<T>(
356 residual: &mut [Vec<T>],
357 level: &[i32],
358 current: usize,
359 sink: usize,
360 visited: &mut [bool],
361 flow: T,
362) -> T
363where
364 T: Float + SparseElement + Debug + Copy + 'static,
365{
366 if current == sink {
367 return flow;
368 }
369
370 visited[current] = true;
371
372 for neighbor in 0..residual.len() {
373 if !visited[neighbor]
374 && residual[current][neighbor] > T::sparse_zero()
375 && level[neighbor] == level[current] + 1
376 {
377 let min_flow = if residual[current][neighbor] < flow {
378 residual[current][neighbor]
379 } else {
380 flow
381 };
382
383 let pushed_flow = send_flow(residual, level, neighbor, sink, visited, min_flow);
384
385 if pushed_flow > T::sparse_zero() {
386 residual[current][neighbor] = residual[current][neighbor] - pushed_flow;
387 residual[neighbor][current] = residual[neighbor][current] + pushed_flow;
388 return pushed_flow;
389 }
390 }
391 }
392
393 T::sparse_zero()
394}
395
396pub fn min_cut<T>(result: &MaxFlowResult<T>, source: usize) -> Vec<bool>
409where
410 T: Float + SparseElement + Debug + Copy + 'static,
411{
412 let n = result.flow_matrix.len();
413 let mut reachable = vec![false; n];
414 let mut queue = VecDeque::new();
415
416 queue.push_back(source);
417 reachable[source] = true;
418
419 while let Some(current) = queue.pop_front() {
420 for neighbor in 0..n {
421 if !reachable[neighbor] && result.flow_matrix[current][neighbor] > T::sparse_zero() {
422 reachable[neighbor] = true;
423 queue.push_back(neighbor);
424 }
425 }
426 }
427
428 reachable
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434 use crate::csr_array::CsrArray;
435 use approx::assert_relative_eq;
436
437 fn create_test_flow_network() -> CsrArray<f64> {
438 let rows = vec![0, 0, 1, 1, 2, 4];
447 let cols = vec![1, 2, 3, 4, 4, 3];
448 let data = vec![10.0, 10.0, 10.0, 10.0, 15.0, 10.0];
449
450 CsrArray::from_triplets(&rows, &cols, &data, (5, 5), false).expect("Failed to create")
451 }
452
453 #[test]
454 fn test_ford_fulkerson() {
455 let graph = create_test_flow_network();
456 let result = ford_fulkerson(&graph, 0, 3).expect("Failed");
457
458 assert!(result.flow_value > 15.0);
460 assert!(result.flow_value <= 20.0);
461 }
462
463 #[test]
464 fn test_edmonds_karp() {
465 let graph = create_test_flow_network();
466 let result = edmonds_karp(&graph, 0, 3).expect("Failed");
467
468 assert!(result.flow_value > 15.0);
470 assert!(result.flow_value <= 20.0);
471 }
472
473 #[test]
474 fn test_dinic() {
475 let graph = create_test_flow_network();
476 let result = dinic(&graph, 0, 3).expect("Failed");
477
478 assert!(result.flow_value > 15.0);
480 assert!(result.flow_value <= 20.0);
481 }
482
483 #[test]
484 fn test_simple_network() {
485 let rows = vec![0, 1];
487 let cols = vec![1, 2];
488 let data = vec![10.0, 5.0];
489
490 let graph = CsrArray::from_triplets(&rows, &cols, &data, (3, 3), false).expect("Failed");
491 let result = edmonds_karp(&graph, 0, 2).expect("Failed");
492
493 assert_relative_eq!(result.flow_value, 5.0, epsilon = 1e-6);
495 }
496
497 #[test]
498 fn test_no_path() {
499 let rows = vec![0, 2];
501 let cols = vec![1, 3];
502 let data = vec![10.0, 10.0];
503
504 let graph = CsrArray::from_triplets(&rows, &cols, &data, (4, 4), false).expect("Failed");
505 let result = edmonds_karp(&graph, 0, 3).expect("Failed");
506
507 assert_relative_eq!(result.flow_value, 0.0, epsilon = 1e-6);
509 }
510
511 #[test]
512 fn test_min_cut() {
513 let graph = create_test_flow_network();
514 let result = edmonds_karp(&graph, 0, 3).expect("Failed");
515 let cut = min_cut(&result, 0);
516
517 assert!(cut[0]);
519
520 assert!(!cut[3]);
522 }
523
524 #[test]
525 fn test_algorithms_agree() {
526 let graph = create_test_flow_network();
527
528 let ff_result = ford_fulkerson(&graph, 0, 3).expect("Failed");
529 let ek_result = edmonds_karp(&graph, 0, 3).expect("Failed");
530 let dinic_result = dinic(&graph, 0, 3).expect("Failed");
531
532 assert_relative_eq!(ff_result.flow_value, ek_result.flow_value, epsilon = 1e-6);
534 assert_relative_eq!(
535 ek_result.flow_value,
536 dinic_result.flow_value,
537 epsilon = 1e-6
538 );
539 }
540}