petgraph/algo/maximum_flow/
dinics.rs1use alloc::{collections::VecDeque, vec, vec::Vec};
2use core::ops::Sub;
3
4use crate::{
5 algo::{EdgeRef, PositiveMeasure},
6 prelude::Direction,
7 visit::{
8 Data, EdgeCount, EdgeIndexable, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
9 NodeCount, NodeIndexable, VisitMap, Visitable,
10 },
11};
12
13pub fn dinics<G>(
74 network: G,
75 source: G::NodeId,
76 destination: G::NodeId,
77) -> (G::EdgeWeight, Vec<G::EdgeWeight>)
78where
79 G: NodeCount + EdgeCount + IntoEdgesDirected + EdgeIndexable + NodeIndexable + Visitable,
80 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
81{
82 let mut max_flow = G::EdgeWeight::zero();
83 let mut flows = vec![G::EdgeWeight::zero(); network.edge_count()];
84 let mut visited = network.visit_map();
85 let mut level_edges = vec![Default::default(); network.node_bound()];
86
87 let dest_index = NodeIndexable::to_index(&network, destination);
88 while build_level_graph(&network, source, destination, &flows, &mut level_edges)[dest_index] > 0
89 {
90 let flow_increase = find_blocking_flow(
91 network,
92 source,
93 destination,
94 &mut flows,
95 &mut level_edges,
96 &mut visited,
97 );
98 max_flow = max_flow + flow_increase;
99 }
100 (max_flow, flows)
101}
102
103fn build_level_graph<G>(
115 network: G,
116 source: G::NodeId,
117 destination: G::NodeId,
118 flows: &[G::EdgeWeight],
119 level_edges: &mut [Vec<G::EdgeRef>],
120) -> Vec<usize>
121where
122 G: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable,
123 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
124{
125 let mut level_graph = vec![0; network.node_bound()];
126 let mut bfs_queue = VecDeque::with_capacity(network.node_count());
127 bfs_queue.push_back(source);
128
129 level_graph[NodeIndexable::to_index(&network, source)] = 1;
130 while let Some(vertex) = bfs_queue.pop_front() {
131 let vertex_index = NodeIndexable::to_index(&network, vertex);
132 let out_edges = network.edges_directed(vertex, Direction::Outgoing);
133 let in_edges = network.edges_directed(vertex, Direction::Incoming);
134 level_edges[vertex_index].clear();
135 for edge in out_edges.chain(in_edges) {
136 let next_vertex = other_endpoint(&network, edge, vertex);
137 let edge_index = EdgeIndexable::to_index(&network, edge.id());
138 let residual_cap = residual_capacity(&network, edge, next_vertex, flows[edge_index]);
139 if residual_cap == G::EdgeWeight::zero() {
140 continue;
141 }
142 let next_vertex_index = NodeIndexable::to_index(&network, next_vertex);
143 if level_graph[next_vertex_index] == 0 {
144 level_graph[next_vertex_index] = level_graph[vertex_index] + 1;
145 level_edges[vertex_index].push(edge);
146 if next_vertex != destination {
147 bfs_queue.push_back(next_vertex);
148 }
149 } else if level_graph[next_vertex_index] == level_graph[vertex_index] + 1 {
150 level_edges[vertex_index].push(edge);
151 }
152 }
153 }
154
155 level_graph
156}
157
158fn find_blocking_flow<G>(
164 network: G,
165 source: G::NodeId,
166 destination: G::NodeId,
167 flows: &mut [G::EdgeWeight],
168 level_edges: &mut [Vec<G::EdgeRef>],
169 visited: &mut G::Map,
170) -> G::EdgeWeight
171where
172 G: NodeCount + IntoEdges + NodeIndexable + EdgeIndexable + Visitable,
173 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
174{
175 let mut flow_increase = G::EdgeWeight::zero();
176 let mut edge_to = vec![None; network.node_bound()];
177 while find_augmenting_path(
178 &network,
179 source,
180 destination,
181 flows,
182 level_edges,
183 visited,
184 &mut edge_to,
185 ) {
186 let mut path_flow = G::EdgeWeight::max();
187
188 let mut vertex = destination;
190 while let Some(edge) = edge_to[NodeIndexable::to_index(&network, vertex)] {
191 let edge_index = EdgeIndexable::to_index(&network, edge.id());
192 let residual_capacity = residual_capacity(&network, edge, vertex, flows[edge_index]);
193 path_flow = min::<G>(path_flow, residual_capacity);
194 vertex = other_endpoint(&network, edge, vertex);
195 }
196
197 let mut vertex = destination;
199 while let Some(edge) = edge_to[NodeIndexable::to_index(&network, vertex)] {
200 let edge_index = EdgeIndexable::to_index(&network, edge.id());
201 flows[edge_index] =
202 adjusted_residual_flow(&network, edge, vertex, flows[edge_index], path_flow);
203 vertex = other_endpoint(&network, edge, vertex);
204 }
205 flow_increase = flow_increase + path_flow;
206 }
207 flow_increase
208}
209
210fn find_augmenting_path<G>(
215 network: G,
216 source: G::NodeId,
217 destination: G::NodeId,
218 flows: &[G::EdgeWeight],
219 level_edges: &mut [Vec<G::EdgeRef>],
220 visited: &mut G::Map,
221 edge_to: &mut [Option<G::EdgeRef>],
222) -> bool
223where
224 G: IntoEdges + NodeIndexable + EdgeIndexable + Visitable,
225 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
226{
227 network.reset_map(visited);
228 let mut level_edges_i = vec![0; level_edges.len()];
229
230 let mut dfs_stack = Vec::new();
231 dfs_stack.push(source);
232 visited.visit(source);
233 while let Some(&vertex) = dfs_stack.last() {
234 let vertex_index = NodeIndexable::to_index(&network, vertex);
235
236 let mut found_next = false;
237 while level_edges_i[vertex_index] < level_edges[vertex_index].len() {
238 let curr_level_edges_i = level_edges_i[vertex_index];
239 let edge = level_edges[vertex_index][curr_level_edges_i];
240 let next_vertex = other_endpoint(&network, edge, vertex);
241
242 let edge_index: usize = EdgeIndexable::to_index(&network, edge.id());
243 let residual_cap = residual_capacity(&network, edge, next_vertex, flows[edge_index]);
244 if residual_cap == G::EdgeWeight::zero() {
245 level_edges[vertex_index].swap_remove(curr_level_edges_i);
246 continue;
247 }
248
249 if !visited.is_visited(&next_vertex) {
250 let next_vertex_index = NodeIndexable::to_index(&network, next_vertex);
251 edge_to[next_vertex_index] = Some(edge);
252 if destination == next_vertex {
253 return true;
254 }
255 dfs_stack.push(next_vertex);
256 visited.visit(next_vertex);
257 found_next = true;
258 break;
259 }
260 level_edges_i[vertex_index] += 1;
261 }
262 if !found_next {
263 dfs_stack.pop();
264 }
265 }
266 false
267}
268
269fn adjusted_residual_flow<G>(
271 network: G,
272 edge: G::EdgeRef,
273 target_vertex: G::NodeId,
274 flow: G::EdgeWeight,
275 flow_increase: G::EdgeWeight,
276) -> G::EdgeWeight
277where
278 G: NodeIndexable + IntoEdges,
279 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
280{
281 if target_vertex == edge.source() {
282 flow - flow_increase
284 } else if target_vertex == edge.target() {
285 flow + flow_increase
287 } else {
288 let end_point = NodeIndexable::to_index(&network, target_vertex);
289 panic!("Illegal endpoint {}", end_point);
290 }
291}
292
293fn residual_capacity<G>(
295 network: G,
296 edge: G::EdgeRef,
297 target_vertex: G::NodeId,
298 flow: G::EdgeWeight,
299) -> G::EdgeWeight
300where
301 G: NodeIndexable + IntoEdges,
302 G::EdgeWeight: Sub<Output = G::EdgeWeight> + PositiveMeasure,
303{
304 if target_vertex == edge.source() {
305 flow
307 } else if target_vertex == edge.target() {
308 *edge.weight() - flow
310 } else {
311 let end_point = NodeIndexable::to_index(&network, target_vertex);
312 panic!("Illegal endpoint {}", end_point);
313 }
314}
315
316fn min<G>(a: G::EdgeWeight, b: G::EdgeWeight) -> G::EdgeWeight
320where
321 G: Data,
322 G::EdgeWeight: PartialOrd,
323{
324 if a < b {
325 a
326 } else if a >= b {
327 b
328 } else {
329 panic!("Invalid edge weights. Impossible to get min value.");
330 }
331}
332
333fn other_endpoint<G>(network: G, edge: G::EdgeRef, vertex: G::NodeId) -> G::NodeId
335where
336 G: NodeIndexable + IntoEdgeReferences,
337{
338 if vertex == edge.source() {
339 edge.target()
340 } else if vertex == edge.target() {
341 edge.source()
342 } else {
343 let end_point = NodeIndexable::to_index(&network, vertex);
344 panic!("Illegal endpoint {}", end_point);
345 }
346}