graph_flow/flow_graph.rs
1//! Index-based residual graph for flow algorithms.
2//!
3//! All flow algorithms in this crate operate on [`FlowGraph`] rather than the
4//! generic [`Graph`] trait. See the [crate-level documentation](crate) for the
5//! design rationale.
6//!
7//! [`Graph`]: graph_core::Graph
8
9/// A single directed edge in a flow network.
10///
11/// Each edge stores its target node, capacity, current flow, and — crucially —
12/// the index of its **reverse edge** in the adjacency list of the target node.
13/// This reverse-index pattern is the standard safe Rust approach to residual
14/// graph updates: instead of holding two mutable references simultaneously, we
15/// use indices to locate and update both the forward and backward edges.
16#[derive(Debug, Clone)]
17pub struct FlowEdge {
18 /// Destination node index.
19 pub to: usize,
20 /// Maximum capacity of this edge.
21 pub capacity: f64,
22 /// Current flow along this edge.
23 pub flow: f64,
24 /// Index of the reverse (residual) edge in `adjacency[to]`.
25 ///
26 /// When we send flow along edge `(u→v)`, we simultaneously increase the
27 /// residual capacity of `(v→u)` by indexing: `adjacency[to][rev]`.
28 pub rev: usize,
29}
30
31impl FlowEdge {
32 /// Returns the **residual capacity** of this edge: how much more flow can
33 /// be pushed along it.
34 ///
35 /// For a forward edge this is `capacity - flow`. For a reverse (residual)
36 /// edge this equals the flow already sent on the corresponding forward
37 /// edge.
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use graph_flow::flow_graph::FlowEdge;
43 ///
44 /// let edge = FlowEdge { to: 1, capacity: 10.0, flow: 3.0, rev: 0 };
45 /// assert_eq!(edge.residual(), 7.0);
46 /// ```
47 #[inline]
48 pub fn residual(&self) -> f64 {
49 self.capacity - self.flow
50 }
51}
52
53/// An index-based directed flow network supporting residual graph operations.
54///
55/// Nodes are identified by `usize` indices `0..n`. Call [`add_edge`] to add a
56/// directed edge; the reverse residual edge is inserted automatically.
57///
58/// # Examples
59///
60/// ```
61/// use graph_flow::FlowGraph;
62///
63/// let mut g = FlowGraph::new(4);
64/// g.add_edge(0, 1, 10.0);
65/// g.add_edge(0, 2, 5.0);
66/// g.add_edge(1, 3, 10.0);
67/// g.add_edge(2, 3, 5.0);
68///
69/// // Node count is what we specified.
70/// assert_eq!(g.node_count(), 4);
71/// // Each add_edge inserts 2 entries (forward + reverse).
72/// assert_eq!(g.adjacency[0].len(), 2);
73/// ```
74///
75/// [`add_edge`]: FlowGraph::add_edge
76#[derive(Debug, Clone)]
77pub struct FlowGraph {
78 /// Adjacency list: `adjacency[u]` is the list of edges leaving node `u`.
79 ///
80 /// Both real (forward) edges and zero-capacity reverse (residual) edges
81 /// are stored here. Use [`FlowEdge::residual`] to check if an edge can
82 /// carry more flow.
83 pub adjacency: Vec<Vec<FlowEdge>>,
84}
85
86impl FlowGraph {
87 /// Creates a new flow graph with `n` nodes and no edges.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// use graph_flow::FlowGraph;
93 ///
94 /// let g = FlowGraph::new(5);
95 /// assert_eq!(g.node_count(), 5);
96 /// ```
97 pub fn new(n: usize) -> Self {
98 Self {
99 adjacency: vec![Vec::new(); n],
100 }
101 }
102
103 /// Returns the number of nodes in the graph.
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// use graph_flow::FlowGraph;
109 ///
110 /// let g = FlowGraph::new(3);
111 /// assert_eq!(g.node_count(), 3);
112 /// ```
113 #[inline]
114 pub fn node_count(&self) -> usize {
115 self.adjacency.len()
116 }
117
118 /// Adds a directed edge from `u` to `v` with the given `capacity`, and
119 /// automatically inserts the corresponding zero-capacity reverse edge
120 /// from `v` to `u`.
121 ///
122 /// The reverse edge index is stored in each [`FlowEdge::rev`] field so
123 /// that augmenting flow along `(u→v)` can update the residual `(v→u)`
124 /// in O(1) using only safe index arithmetic.
125 ///
126 /// # Panics
127 ///
128 /// Panics if `u` or `v` is out of bounds (`>= node_count()`).
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use graph_flow::FlowGraph;
134 ///
135 /// let mut g = FlowGraph::new(2);
136 /// g.add_edge(0, 1, 15.0);
137 ///
138 /// // Forward edge from 0 to 1.
139 /// assert_eq!(g.adjacency[0][0].to, 1);
140 /// assert_eq!(g.adjacency[0][0].capacity, 15.0);
141 ///
142 /// // Reverse edge from 1 to 0 (zero capacity).
143 /// assert_eq!(g.adjacency[1][0].to, 0);
144 /// assert_eq!(g.adjacency[1][0].capacity, 0.0);
145 /// ```
146 pub fn add_edge(&mut self, u: usize, v: usize, capacity: f64) {
147 // Index of the forward edge in adjacency[u].
148 let forward_idx = self.adjacency[u].len();
149 // Index of the reverse edge in adjacency[v].
150 let reverse_idx = self.adjacency[v].len();
151
152 self.adjacency[u].push(FlowEdge {
153 to: v,
154 capacity,
155 flow: 0.0,
156 rev: reverse_idx,
157 });
158 self.adjacency[v].push(FlowEdge {
159 to: u,
160 capacity: 0.0, // reverse edge starts with zero capacity
161 flow: 0.0,
162 rev: forward_idx,
163 });
164 }
165
166 /// Sends `amount` of flow along the edge at `adjacency[u][edge_idx]` and
167 /// simultaneously updates the corresponding reverse edge.
168 ///
169 /// This is the primitive used by augmenting-path algorithms after
170 /// identifying the bottleneck capacity of a path.
171 ///
172 /// # Panics
173 ///
174 /// Panics if `u` or `edge_idx` is out of bounds.
175 pub fn push_flow(&mut self, u: usize, edge_idx: usize, amount: f64) {
176 let rev_node = self.adjacency[u][edge_idx].to;
177 let rev_idx = self.adjacency[u][edge_idx].rev;
178
179 self.adjacency[u][edge_idx].flow += amount;
180 self.adjacency[rev_node][rev_idx].flow -= amount;
181 }
182
183 /// Resets all flow values to zero, restoring the graph to its initial
184 /// state with full capacity on every forward edge.
185 ///
186 /// Useful for running multiple flow algorithms on the same graph without
187 /// rebuilding it from scratch.
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use graph_flow::{FlowGraph, ford_fulkerson};
193 ///
194 /// let mut g = FlowGraph::new(2);
195 /// g.add_edge(0, 1, 10.0);
196 ///
197 /// let flow = ford_fulkerson(&mut g, 0, 1);
198 /// assert_eq!(flow, 10.0);
199 ///
200 /// g.reset_flow();
201 /// assert_eq!(g.adjacency[0][0].flow, 0.0);
202 /// ```
203 pub fn reset_flow(&mut self) {
204 for adj in &mut self.adjacency {
205 for edge in adj {
206 edge.flow = 0.0;
207 }
208 }
209 }
210}