1 use std::{collections::VecDeque, ops::Sub};
2 
3 use crate::{
4     data::DataMap,
5     visit::{
6         EdgeCount, EdgeIndexable, IntoEdges, IntoEdgesDirected, NodeCount, NodeIndexable, VisitMap,
7         Visitable,
8     },
9 };
10 
11 use super::{EdgeRef, PositiveMeasure};
12 use crate::prelude::Direction;
13 
residual_capacity<N>( network: N, edge: N::EdgeRef, vertex: N::NodeId, flow: N::EdgeWeight, ) -> N::EdgeWeight where N: NodeIndexable + IntoEdges, N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,14 fn residual_capacity<N>(
15     network: N,
16     edge: N::EdgeRef,
17     vertex: N::NodeId,
18     flow: N::EdgeWeight,
19 ) -> N::EdgeWeight
20 where
21     N: NodeIndexable + IntoEdges,
22     N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
23 {
24     if vertex == edge.source() {
25         // backward edge
26         flow
27     } else if vertex == edge.target() {
28         // forward edge
29         return *edge.weight() - flow;
30     } else {
31         let end_point = NodeIndexable::to_index(&network, vertex);
32         panic!("Illegal endpoint {}", end_point);
33     }
34 }
35 
36 /// Gets the other endpoint of graph edge, if any, otherwise panics.
other_endpoint<N>(network: N, edge: N::EdgeRef, vertex: N::NodeId) -> N::NodeId where N: NodeIndexable + IntoEdges,37 fn other_endpoint<N>(network: N, edge: N::EdgeRef, vertex: N::NodeId) -> N::NodeId
38 where
39     N: NodeIndexable + IntoEdges,
40 {
41     if vertex == edge.source() {
42         edge.target()
43     } else if vertex == edge.target() {
44         edge.source()
45     } else {
46         let end_point = NodeIndexable::to_index(&network, vertex);
47         panic!("Illegal endpoint {}", end_point);
48     }
49 }
50 
51 /// Tells whether there is an augmented path in the graph
has_augmented_path<N>( network: N, source: N::NodeId, destination: N::NodeId, edge_to: &mut [Option<N::EdgeRef>], flows: &[N::EdgeWeight], ) -> bool where N: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable + Visitable, N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,52 fn has_augmented_path<N>(
53     network: N,
54     source: N::NodeId,
55     destination: N::NodeId,
56     edge_to: &mut [Option<N::EdgeRef>],
57     flows: &[N::EdgeWeight],
58 ) -> bool
59 where
60     N: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable + Visitable,
61     N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
62 {
63     let mut visited = network.visit_map();
64     let mut queue = VecDeque::new();
65     visited.visit(source);
66     queue.push_back(source);
67 
68     while let Some(vertex) = queue.pop_front() {
69         let out_edges = network.edges_directed(vertex, Direction::Outgoing);
70         let in_edges = network.edges_directed(vertex, Direction::Incoming);
71         for edge in out_edges.chain(in_edges) {
72             let next = other_endpoint(&network, edge, vertex);
73             let edge_index: usize = EdgeIndexable::to_index(&network, edge.id());
74             let residual_cap = residual_capacity(&network, edge, next, flows[edge_index]);
75             if !visited.is_visited(&next) && (residual_cap > N::EdgeWeight::zero()) {
76                 visited.visit(next);
77                 edge_to[NodeIndexable::to_index(&network, next)] = Some(edge);
78                 if destination == next {
79                     return true;
80                 }
81                 queue.push_back(next);
82             }
83         }
84     }
85     false
86 }
87 
adjust_residual_flow<N>( network: N, edge: N::EdgeRef, vertex: N::NodeId, flow: N::EdgeWeight, delta: N::EdgeWeight, ) -> N::EdgeWeight where N: NodeIndexable + IntoEdges, N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,88 fn adjust_residual_flow<N>(
89     network: N,
90     edge: N::EdgeRef,
91     vertex: N::NodeId,
92     flow: N::EdgeWeight,
93     delta: N::EdgeWeight,
94 ) -> N::EdgeWeight
95 where
96     N: NodeIndexable + IntoEdges,
97     N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
98 {
99     if vertex == edge.source() {
100         // backward edge
101         flow - delta
102     } else if vertex == edge.target() {
103         // forward edge
104         flow + delta
105     } else {
106         let end_point = NodeIndexable::to_index(&network, vertex);
107         panic!("Illegal endpoint {}", end_point);
108     }
109 }
110 
111 /// \[Generic\] Ford-Fulkerson algorithm.
112 ///
113 /// Computes the [maximum flow][ff] of a weighted directed graph.
114 ///
115 /// If it terminates, it returns the maximum flow and also the computed edge flows.
116 ///
117 /// [ff]: https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
118 ///
119 /// # Example
120 /// ```rust
121 /// use petgraph::Graph;
122 /// use petgraph::algo::ford_fulkerson;
123 /// // Example from CLRS book
124 /// let mut graph = Graph::<u8, u8>::new();
125 /// let source = graph.add_node(0);
126 /// let _ = graph.add_node(1);
127 /// let _ = graph.add_node(2);
128 /// let _ = graph.add_node(3);
129 /// let _ = graph.add_node(4);
130 /// let destination = graph.add_node(5);
131 /// graph.extend_with_edges(&[
132 ///    (0, 1, 16),
133 ///    (0, 2, 13),
134 ///    (1, 2, 10),
135 ///    (1, 3, 12),
136 ///    (2, 1, 4),
137 ///    (2, 4, 14),
138 ///    (3, 2, 9),
139 ///    (3, 5, 20),
140 ///    (4, 3, 7),
141 ///    (4, 5, 4),
142 /// ]);
143 /// let (max_flow, _) = ford_fulkerson(&graph, source, destination);
144 /// assert_eq!(23, max_flow);
145 /// ```
ford_fulkerson<N>( network: N, source: N::NodeId, destination: N::NodeId, ) -> (N::EdgeWeight, Vec<N::EdgeWeight>) where N: NodeCount + EdgeCount + IntoEdgesDirected + EdgeIndexable + NodeIndexable + DataMap + Visitable, N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,146 pub fn ford_fulkerson<N>(
147     network: N,
148     source: N::NodeId,
149     destination: N::NodeId,
150 ) -> (N::EdgeWeight, Vec<N::EdgeWeight>)
151 where
152     N: NodeCount
153         + EdgeCount
154         + IntoEdgesDirected
155         + EdgeIndexable
156         + NodeIndexable
157         + DataMap
158         + Visitable,
159     N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
160 {
161     let mut edge_to = vec![None; network.node_count()];
162     let mut flows = vec![N::EdgeWeight::zero(); network.edge_count()];
163     let mut max_flow = N::EdgeWeight::zero();
164     while has_augmented_path(&network, source, destination, &mut edge_to, &flows) {
165         let mut path_flow = N::EdgeWeight::max();
166 
167         // Find the bottleneck capacity of the path
168         let mut vertex = destination;
169         let mut vertex_index = NodeIndexable::to_index(&network, vertex);
170         while let Some(edge) = edge_to[vertex_index] {
171             let edge_index = EdgeIndexable::to_index(&network, edge.id());
172             let residual_capacity = residual_capacity(&network, edge, vertex, flows[edge_index]);
173             // Minimum between the current path flow and the residual capacity.
174             path_flow = if path_flow > residual_capacity {
175                 residual_capacity
176             } else {
177                 path_flow
178             };
179             vertex = other_endpoint(&network, edge, vertex);
180             vertex_index = NodeIndexable::to_index(&network, vertex);
181         }
182 
183         // Update the flow of each edge along the path
184         let mut vertex = destination;
185         let mut vertex_index = NodeIndexable::to_index(&network, vertex);
186         while let Some(edge) = edge_to[vertex_index] {
187             let edge_index = EdgeIndexable::to_index(&network, edge.id());
188             flows[edge_index] =
189                 adjust_residual_flow(&network, edge, vertex, flows[edge_index], path_flow);
190             vertex = other_endpoint(&network, edge, vertex);
191             vertex_index = NodeIndexable::to_index(&network, vertex);
192         }
193         max_flow = max_flow + path_flow;
194     }
195     (max_flow, flows)
196 }
197