Skip to main content

weavatrix_graph/algo/flow/
core.rs

1use super::cut::{indexed_nodes, residual_reachable};
2use crate::Vec;
3use crate::{GraphError, IndexGraphView, Result};
4use alloc::collections::VecDeque;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct MaxFlow<Node, Edge> {
8    value: u64,
9    edge_flows: Vec<(Edge, u64)>,
10    source_side: Vec<Node>,
11}
12
13impl<Node, Edge> MaxFlow<Node, Edge> {
14    pub(super) fn from_parts(
15        value: u64,
16        edge_flows: Vec<(Edge, u64)>,
17        source_side: Vec<Node>,
18    ) -> Self {
19        Self {
20            value,
21            edge_flows,
22            source_side,
23        }
24    }
25
26    #[must_use]
27    pub const fn value(&self) -> u64 {
28        self.value
29    }
30
31    #[must_use]
32    pub fn edge_flows(&self) -> &[(Edge, u64)] {
33        &self.edge_flows
34    }
35
36    #[must_use]
37    pub fn source_side(&self) -> &[Node] {
38        &self.source_side
39    }
40}
41
42/// Computes a directed maximum flow with Dinic's blocking-flow algorithm.
43///
44/// The returned source-side residual partition also describes a minimum cut.
45///
46/// # Errors
47///
48/// Returns an error if the total flow is larger than `u64::MAX`.
49pub fn maximum_flow<G, F>(
50    graph: &G,
51    source: G::Node,
52    sink: G::Node,
53    mut edge_capacity: F,
54) -> Result<Option<MaxFlow<G::Node, G::Edge>>>
55where
56    G: IndexGraphView,
57    F: FnMut(G::Edge) -> u64,
58{
59    if !graph.contains_node(source) || !graph.contains_node(sink) {
60        return Ok(None);
61    }
62    let mut capacities = vec![0_u64; graph.edge_bound()];
63    let mut edge_order = Vec::with_capacity(graph.edge_count());
64    for edge in graph.edge_indices() {
65        capacities[G::edge_slot(edge)] = edge_capacity(edge);
66        edge_order.push(edge);
67    }
68    if source == sink {
69        return Ok(Some(MaxFlow {
70            value: 0,
71            edge_flows: edge_order.into_iter().map(|edge| (edge, 0)).collect(),
72            source_side: vec![source],
73        }));
74    }
75
76    let mut flows = vec![0_u64; graph.edge_bound()];
77    let mut levels = vec![-1_i32; graph.node_bound()];
78    let mut level_edges = vec![Vec::new(); graph.node_bound()];
79    let mut total = 0_u64;
80    while build_levels(
81        graph,
82        source,
83        sink,
84        &capacities,
85        &flows,
86        &mut levels,
87        &mut level_edges,
88    ) {
89        let mut next = vec![0_usize; graph.node_bound()];
90        loop {
91            let pushed = augment_level_path::<G>(
92                G::node_slot(source),
93                G::node_slot(sink),
94                &level_edges,
95                &mut next,
96                &capacities,
97                &mut flows,
98            );
99            if pushed == 0 {
100                break;
101            }
102            total = total
103                .checked_add(pushed)
104                .ok_or(GraphError::ArithmeticOverflow {
105                    operation: "maximum flow",
106                })?;
107        }
108    }
109
110    let edge_flows = edge_order
111        .into_iter()
112        .map(|edge| (edge, flows[G::edge_slot(edge)]))
113        .collect();
114    let reachable = residual_reachable(graph, source, &capacities, &flows);
115    let source_side = graph
116        .node_indices()
117        .filter(|node| reachable[G::node_slot(*node)])
118        .collect();
119    Ok(Some(MaxFlow {
120        value: total,
121        edge_flows,
122        source_side,
123    }))
124}
125
126#[derive(Clone, Copy)]
127struct ResidualEdge<Edge> {
128    edge: Edge,
129    target: usize,
130    forward: bool,
131}
132
133fn build_levels<G>(
134    graph: &G,
135    source: G::Node,
136    sink: G::Node,
137    capacities: &[u64],
138    flows: &[u64],
139    levels: &mut [i32],
140    level_edges: &mut [Vec<ResidualEdge<G::Edge>>],
141) -> bool
142where
143    G: IndexGraphView,
144{
145    levels.fill(-1);
146    for edges in &mut *level_edges {
147        edges.clear();
148    }
149    let source = G::node_slot(source);
150    let sink = G::node_slot(sink);
151    levels[source] = 0;
152    let mut queue = VecDeque::from([source]);
153    let nodes = indexed_nodes(graph);
154    while let Some(node) = queue.pop_front() {
155        let Some(node_key) = nodes[node] else {
156            continue;
157        };
158        for edge in graph.outgoing_edges(node_key) {
159            let slot = G::edge_slot(edge);
160            if capacities[slot] > flows[slot] {
161                let target = graph
162                    .edge_endpoints(edge)
163                    .map(|endpoints| G::node_slot(endpoints.target()));
164                add_level_edge(edge, target, true, node, levels, level_edges, &mut queue);
165            }
166        }
167        for edge in graph.incoming_edges(node_key) {
168            let slot = G::edge_slot(edge);
169            if flows[slot] > 0 {
170                let target = graph
171                    .edge_endpoints(edge)
172                    .map(|endpoints| G::node_slot(endpoints.source()));
173                add_level_edge(edge, target, false, node, levels, level_edges, &mut queue);
174            }
175        }
176    }
177    levels[sink] >= 0
178}
179
180fn add_level_edge<Edge: Copy>(
181    edge: Edge,
182    target: Option<usize>,
183    forward: bool,
184    source: usize,
185    levels: &mut [i32],
186    level_edges: &mut [Vec<ResidualEdge<Edge>>],
187    queue: &mut VecDeque<usize>,
188) {
189    let Some(target) = target else {
190        return;
191    };
192    if levels[target] < 0 {
193        levels[target] = levels[source] + 1;
194        queue.push_back(target);
195    }
196    if levels[target] == levels[source] + 1 {
197        level_edges[source].push(ResidualEdge {
198            edge,
199            target,
200            forward,
201        });
202    }
203}
204
205fn augment_level_path<G>(
206    source: usize,
207    sink: usize,
208    level_edges: &[Vec<ResidualEdge<G::Edge>>],
209    next: &mut [usize],
210    capacities: &[u64],
211    flows: &mut [u64],
212) -> u64
213where
214    G: IndexGraphView,
215{
216    let mut nodes = vec![source];
217    let mut path: Vec<ResidualEdge<G::Edge>> = Vec::new();
218    loop {
219        let node = *nodes.last().unwrap_or(&source);
220        if node == sink {
221            let amount = path
222                .iter()
223                .map(|step| residual::<G>(*step, capacities, flows))
224                .min()
225                .unwrap_or(0);
226            for step in &path {
227                let slot = G::edge_slot(step.edge);
228                if step.forward {
229                    flows[slot] += amount;
230                } else {
231                    flows[slot] -= amount;
232                }
233            }
234            return amount;
235        }
236        let Some(&step) = level_edges[node].get(next[node]) else {
237            if node == source {
238                return 0;
239            }
240            nodes.pop();
241            path.pop();
242            let parent = *nodes.last().unwrap_or(&source);
243            next[parent] += 1;
244            continue;
245        };
246        if residual::<G>(step, capacities, flows) > 0 {
247            nodes.push(step.target);
248            path.push(step);
249        } else {
250            next[node] += 1;
251        }
252    }
253}
254
255fn residual<G>(step: ResidualEdge<G::Edge>, capacities: &[u64], flows: &[u64]) -> u64
256where
257    G: IndexGraphView,
258{
259    let slot = G::edge_slot(step.edge);
260    if step.forward {
261        capacities[slot] - flows[slot]
262    } else {
263        flows[slot]
264    }
265}