gomory_hu_tree/flow/
graph.rs

1use petgraph::graph::{Graph, NodeIndex};
2use petgraph::visit::EdgeRef;
3use petgraph::Directed;
4use std::marker::PhantomData;
5
6use super::traits::{FlowGraph, OriginalGraphView};
7
8/// An adapter for `petgraph::Graph` to be used as a `FlowGraph` and `OriginalGraphView`.
9///
10/// This graph is directed. Edge weights are `f64` representing capacities.
11/// Node weights are generic (`N`), defaulting to `()`.
12///
13/// It assumes that vertex indices used by algorithms (`usize`) correspond directly to
14/// `petgraph::NodeIndex::index()` values. This holds if nodes are added and not removed.
15#[derive(Debug, Clone)]
16pub struct AdjacencyListFlowGraph<N = ()>
17where
18    N: Clone + std::fmt::Debug,
19{
20    /// The internal `petgraph::Graph` instance.
21    graph: Graph<N, f64, Directed, u32>,
22    _phantom_n: PhantomData<N>,
23}
24
25impl<N> AdjacencyListFlowGraph<N>
26where
27    N: Clone + std::fmt::Debug,
28{
29    /// Creates a new, empty `AdjacencyListFlowGraph`.
30    pub fn new() -> Self {
31        Self {
32            graph: Graph::default(), // Graph::default() is Directed
33            _phantom_n: PhantomData,
34        }
35    }
36
37    /// Adds a new node with the given weight to the graph.
38    ///
39    /// # Arguments
40    /// * `weight`: The weight of the node (e.g., `()` if no specific data is needed).
41    ///
42    /// # Returns
43    /// The `usize` index of the newly added node. This index is what should be used
44    /// in `add_edge` calls and by flow algorithms.
45    pub fn add_node(&mut self, weight: N) -> usize {
46        self.graph.add_node(weight).index()
47    }
48
49    /// Adds a directed edge to the graph.
50    ///
51    /// # Arguments
52    /// * `u_idx`: The `usize` index of the source node (previously returned by `add_node`).
53    /// * `v_idx`: The `usize` index of the target node (previously returned by `add_node`).
54    /// * `capacity`: The capacity of the edge (must be `f64`).
55    ///
56    /// # Panics
57    /// Panics if `u_idx` or `v_idx` do not correspond to existing nodes in the graph,
58    /// or if they are out of bounds for the current node count.
59    /// `petgraph` itself panics if `NodeIndex`s are invalid.
60    pub fn add_edge(&mut self, u_idx: usize, v_idx: usize, capacity: f64) {
61        // Ensure indices are within the current node count before creating NodeIndex.
62        // This prevents panics from NodeIndex::new if idx is too large,
63        // though petgraph.add_edge would panic anyway if node doesn't exist.
64        let node_count = self.graph.node_count();
65        if u_idx >= node_count || v_idx >= node_count {
66            panic!("Attempted to add edge with out-of-bounds vertex index. u_idx: {u_idx}, v_idx: {v_idx}, node_count: {node_count}");
67        }
68        let u_node = NodeIndex::new(u_idx);
69        let v_node = NodeIndex::new(v_idx);
70
71        self.graph.add_edge(u_node, v_node, capacity);
72    }
73}
74
75/// Implements `FlowGraph` for `AdjacencyListFlowGraph`.
76impl<N> FlowGraph for AdjacencyListFlowGraph<N>
77where
78    N: Clone + std::fmt::Debug,
79{
80    /// Returns the number of vertices in the graph.
81    fn vertex_count(&self) -> usize {
82        self.graph.node_count()
83    }
84}
85
86/// Implements `OriginalGraphView` for `AdjacencyListFlowGraph`.
87impl<N> OriginalGraphView for AdjacencyListFlowGraph<N>
88where
89    N: Clone + std::fmt::Debug,
90{
91    /// Returns an iterator over all edges in the graph, yielding tuples of
92    /// `(source_idx, target_idx, capacity)`.
93    ///
94    /// Vertex indices are `usize`.
95    fn all_edges(&self) -> Box<dyn Iterator<Item = (usize, usize, f64)> + '_> {
96        Box::new(self.graph.edge_references().map(|edge_ref| {
97            (
98                edge_ref.source().index(), // NodeIndex::index() gives usize
99                edge_ref.target().index(), // NodeIndex::index() gives usize
100                *edge_ref.weight(),        // Dereference to get f64 capacity
101            )
102        }))
103    }
104}
105
106/// Default implementation for `AdjacencyListFlowGraph`.
107/// Creates an empty graph. Requires `N` to implement `Default`.
108impl<N> Default for AdjacencyListFlowGraph<N>
109where
110    N: Default + Clone + std::fmt::Debug,
111{
112    fn default() -> Self {
113        Self {
114            graph: Graph::default(),
115            _phantom_n: PhantomData,
116        }
117    }
118}