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}