petgraph/algo/
ford_fulkerson.rs
1use alloc::{collections::VecDeque, vec, vec::Vec};
2use core::ops::Sub;
3
4use crate::{
5 data::DataMap,
6 visit::{
7 EdgeCount, EdgeIndexable, IntoEdges, IntoEdgesDirected, NodeCount, NodeIndexable, VisitMap,
8 Visitable,
9 },
10};
11
12use super::{EdgeRef, PositiveMeasure};
13use crate::prelude::Direction;
14
15fn residual_capacity<N>(
16 network: N,
17 edge: N::EdgeRef,
18 vertex: N::NodeId,
19 flow: N::EdgeWeight,
20) -> N::EdgeWeight
21where
22 N: NodeIndexable + IntoEdges,
23 N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
24{
25 if vertex == edge.source() {
26 flow
28 } else if vertex == edge.target() {
29 return *edge.weight() - flow;
31 } else {
32 let end_point = NodeIndexable::to_index(&network, vertex);
33 panic!("Illegal endpoint {}", end_point);
34 }
35}
36
37fn other_endpoint<N>(network: N, edge: N::EdgeRef, vertex: N::NodeId) -> N::NodeId
39where
40 N: NodeIndexable + IntoEdges,
41{
42 if vertex == edge.source() {
43 edge.target()
44 } else if vertex == edge.target() {
45 edge.source()
46 } else {
47 let end_point = NodeIndexable::to_index(&network, vertex);
48 panic!("Illegal endpoint {}", end_point);
49 }
50}
51
52fn has_augmented_path<N>(
54 network: N,
55 source: N::NodeId,
56 destination: N::NodeId,
57 edge_to: &mut [Option<N::EdgeRef>],
58 flows: &[N::EdgeWeight],
59) -> bool
60where
61 N: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable + Visitable,
62 N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
63{
64 let mut visited = network.visit_map();
65 let mut queue = VecDeque::new();
66 visited.visit(source);
67 queue.push_back(source);
68
69 while let Some(vertex) = queue.pop_front() {
70 let out_edges = network.edges_directed(vertex, Direction::Outgoing);
71 let in_edges = network.edges_directed(vertex, Direction::Incoming);
72 for edge in out_edges.chain(in_edges) {
73 let next = other_endpoint(&network, edge, vertex);
74 let edge_index: usize = EdgeIndexable::to_index(&network, edge.id());
75 let residual_cap = residual_capacity(&network, edge, next, flows[edge_index]);
76 if !visited.is_visited(&next) && (residual_cap > N::EdgeWeight::zero()) {
77 visited.visit(next);
78 edge_to[NodeIndexable::to_index(&network, next)] = Some(edge);
79 if destination == next {
80 return true;
81 }
82 queue.push_back(next);
83 }
84 }
85 }
86 false
87}
88
89fn adjust_residual_flow<N>(
90 network: N,
91 edge: N::EdgeRef,
92 vertex: N::NodeId,
93 flow: N::EdgeWeight,
94 delta: N::EdgeWeight,
95) -> N::EdgeWeight
96where
97 N: NodeIndexable + IntoEdges,
98 N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
99{
100 if vertex == edge.source() {
101 flow - delta
103 } else if vertex == edge.target() {
104 flow + delta
106 } else {
107 let end_point = NodeIndexable::to_index(&network, vertex);
108 panic!("Illegal endpoint {}", end_point);
109 }
110}
111
112pub fn ford_fulkerson<N>(
148 network: N,
149 source: N::NodeId,
150 destination: N::NodeId,
151) -> (N::EdgeWeight, Vec<N::EdgeWeight>)
152where
153 N: NodeCount
154 + EdgeCount
155 + IntoEdgesDirected
156 + EdgeIndexable
157 + NodeIndexable
158 + DataMap
159 + Visitable,
160 N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
161{
162 let mut edge_to = vec![None; network.node_count()];
163 let mut flows = vec![N::EdgeWeight::zero(); network.edge_count()];
164 let mut max_flow = N::EdgeWeight::zero();
165 while has_augmented_path(&network, source, destination, &mut edge_to, &flows) {
166 let mut path_flow = N::EdgeWeight::max();
167
168 let mut vertex = destination;
170 let mut vertex_index = NodeIndexable::to_index(&network, vertex);
171 while let Some(edge) = edge_to[vertex_index] {
172 let edge_index = EdgeIndexable::to_index(&network, edge.id());
173 let residual_capacity = residual_capacity(&network, edge, vertex, flows[edge_index]);
174 path_flow = if path_flow > residual_capacity {
176 residual_capacity
177 } else {
178 path_flow
179 };
180 vertex = other_endpoint(&network, edge, vertex);
181 vertex_index = NodeIndexable::to_index(&network, vertex);
182 }
183
184 let mut vertex = destination;
186 let mut vertex_index = NodeIndexable::to_index(&network, vertex);
187 while let Some(edge) = edge_to[vertex_index] {
188 let edge_index = EdgeIndexable::to_index(&network, edge.id());
189 flows[edge_index] =
190 adjust_residual_flow(&network, edge, vertex, flows[edge_index], path_flow);
191 vertex = other_endpoint(&network, edge, vertex);
192 vertex_index = NodeIndexable::to_index(&network, vertex);
193 }
194 max_flow = max_flow + path_flow;
195 }
196 (max_flow, flows)
197}