toolbox_rs/
static_graph.rs

1use crate::{
2    edge::{Edge, EdgeData},
3    graph::{EdgeArrayEntry, EdgeID, Graph, NodeID},
4};
5use core::{cmp::max, ops::Range};
6
7pub struct NodeArrayEntry {
8    pub first_edge: EdgeID,
9}
10
11impl NodeArrayEntry {
12    pub fn new(first_edge: EdgeID) -> NodeArrayEntry {
13        NodeArrayEntry { first_edge }
14    }
15}
16pub struct StaticGraph<T: Ord + Clone> {
17    node_array: Vec<NodeArrayEntry>,
18    edge_array: Vec<EdgeArrayEntry<T>>,
19}
20
21impl<T: Ord + Clone> Default for StaticGraph<T> {
22    fn default() -> Self {
23        Self {
24            node_array: Vec::new(),
25            edge_array: Vec::new(),
26        }
27    }
28}
29
30impl<T: Ord + Copy> StaticGraph<T> {
31    // In time O(V+E) check that the following invariants hold:
32    // a) the target node of each edge is smaller than the number of nodes
33    // b) index values for nodes first_edges are strictly increasing
34    pub fn check_integrity(&self) -> bool {
35        self.edge_array
36            .iter()
37            .all(|edge_entry| (edge_entry.target) < self.number_of_nodes())
38            && self
39                .node_array
40                .windows(2)
41                .all(|pair| pair[0].first_edge <= pair[1].first_edge)
42    }
43
44    pub fn new(mut input: Vec<impl Edge<ID = NodeID> + EdgeData<DATA = T> + Ord>) -> Self {
45        // sort input edges by source/target/data
46        // TODO(dl): sorting by source suffices to construct adjacency array
47        input.sort();
48
49        Self::new_from_sorted_list(input)
50    }
51
52    pub fn new_from_sorted_list(
53        input: Vec<impl Edge<ID = NodeID> + EdgeData<DATA = T> + Ord>,
54    ) -> Self {
55        // TODO: renumber IDs if necessary
56        let number_of_edges = input.len();
57        let mut number_of_nodes = 0;
58        for edge in &input {
59            number_of_nodes = max(edge.source(), number_of_nodes);
60            number_of_nodes = max(edge.target(), number_of_nodes);
61        }
62
63        let mut graph = Self::default();
64        // +1 as we are going to add one sentinel node at the end
65        graph.node_array.reserve(number_of_nodes + 1);
66        graph.edge_array.reserve(number_of_edges);
67
68        // add first entry manually, rest will be computed
69        graph.node_array.push(NodeArrayEntry::new(0));
70        let mut offset = 0;
71        for i in 0..(number_of_nodes) {
72            while offset != input.len() && input[offset].source() == i {
73                offset += 1;
74            }
75            graph.node_array.push(NodeArrayEntry::new(offset as EdgeID));
76        }
77
78        // add sentinel at the end of the node array
79        graph
80            .node_array
81            .push(NodeArrayEntry::new((input.len()) as EdgeID));
82
83        graph.edge_array = input
84            .iter()
85            .map(move |edge| EdgeArrayEntry {
86                target: edge.target(),
87                data: *edge.data(),
88            })
89            .collect();
90        debug_assert!(graph.check_integrity());
91        graph
92    }
93}
94
95impl<T: Ord + Copy> Graph<T> for StaticGraph<T> {
96    fn node_range(&self) -> Range<NodeID> {
97        Range {
98            start: 0,
99            end: self.number_of_nodes() as NodeID,
100        }
101    }
102
103    fn edge_range(&self, n: NodeID) -> Range<EdgeID> {
104        Range {
105            start: self.begin_edges(n),
106            end: self.end_edges(n),
107        }
108    }
109
110    fn number_of_nodes(&self) -> usize {
111        self.node_array.len() - 1
112    }
113
114    fn number_of_edges(&self) -> usize {
115        self.edge_array.len()
116    }
117
118    fn begin_edges(&self, n: NodeID) -> EdgeID {
119        self.node_array[n].first_edge
120    }
121
122    fn end_edges(&self, n: NodeID) -> EdgeID {
123        self.node_array[n + 1].first_edge
124    }
125
126    fn out_degree(&self, n: NodeID) -> usize {
127        let up = self.end_edges(n);
128        let down = self.begin_edges(n);
129        up - down
130    }
131
132    fn target(&self, e: EdgeID) -> NodeID {
133        self.edge_array[e].target
134    }
135
136    fn data(&self, e: EdgeID) -> &T {
137        &self.edge_array[e].data
138    }
139
140    fn data_mut(&mut self, e: EdgeID) -> &mut T {
141        &mut self.edge_array[e].data
142    }
143
144    fn find_edge(&self, s: NodeID, t: NodeID) -> Option<EdgeID> {
145        if s > self.number_of_nodes() {
146            return None;
147        }
148        self.edge_range(s).find(|&edge| self.target(edge) == t)
149    }
150
151    fn find_edge_unchecked(&self, s: NodeID, t: NodeID) -> EdgeID {
152        if s > self.number_of_nodes() {
153            return EdgeID::MAX;
154        }
155        for edge in self.edge_range(s) {
156            if self.target(edge) == t {
157                return edge;
158            }
159        }
160        EdgeID::MAX
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use crate::edge::InputEdge;
167
168    use crate::graph::EdgeID;
169    use crate::{graph::Graph, static_graph::StaticGraph};
170
171    #[test]
172    fn size() {
173        type Graph = StaticGraph<i32>;
174        let edges = vec![
175            InputEdge::new(0, 1, 3),
176            InputEdge::new(1, 2, 3),
177            InputEdge::new(4, 2, 1),
178            InputEdge::new(2, 3, 6),
179            InputEdge::new(0, 4, 2),
180            InputEdge::new(4, 5, 2),
181            InputEdge::new(5, 3, 7),
182            InputEdge::new(1, 5, 2),
183        ];
184        let graph = Graph::new(edges);
185        assert_eq!(6, graph.number_of_nodes());
186        assert_eq!(8, graph.number_of_edges());
187    }
188
189    #[test]
190    fn degree() {
191        type Graph = StaticGraph<i32>;
192        let edges = vec![
193            InputEdge::new(0, 1, 3),
194            InputEdge::new(1, 2, 3),
195            InputEdge::new(4, 2, 1),
196            InputEdge::new(2, 3, 6),
197            InputEdge::new(0, 4, 2),
198            InputEdge::new(4, 5, 2),
199            InputEdge::new(5, 3, 7),
200            InputEdge::new(1, 5, 2),
201        ];
202
203        let graph = Graph::new(edges);
204        let mut sum = 0;
205        for i in graph.node_range() {
206            sum += graph.out_degree(i);
207        }
208        assert_eq!(sum, graph.number_of_edges());
209    }
210
211    #[test]
212    fn find_edge() {
213        type Graph = StaticGraph<i32>;
214        let edges = vec![
215            InputEdge::new(0, 1, 3),
216            InputEdge::new(1, 2, 3),
217            InputEdge::new(4, 2, 1),
218            InputEdge::new(2, 3, 6),
219            InputEdge::new(0, 4, 2),
220            InputEdge::new(4, 5, 2),
221            InputEdge::new(5, 3, 7),
222            InputEdge::new(1, 5, 2),
223        ];
224
225        let graph = Graph::new(edges);
226
227        // existing edges
228        assert!(graph.find_edge_unchecked(0, 1) != EdgeID::MAX);
229        assert!(graph.find_edge_unchecked(1, 2) != EdgeID::MAX);
230        assert!(graph.find_edge_unchecked(4, 2) != EdgeID::MAX);
231        assert!(graph.find_edge_unchecked(2, 3) != EdgeID::MAX);
232        assert!(graph.find_edge_unchecked(0, 4) != EdgeID::MAX);
233        assert!(graph.find_edge_unchecked(4, 5) != EdgeID::MAX);
234        assert!(graph.find_edge_unchecked(5, 3) != EdgeID::MAX);
235        assert!(graph.find_edge_unchecked(1, 5) != EdgeID::MAX);
236        assert!(graph.find_edge(0, 1).is_some());
237        assert!(graph.find_edge(1, 2).is_some());
238        assert!(graph.find_edge(4, 2).is_some());
239        assert!(graph.find_edge(2, 3).is_some());
240        assert!(graph.find_edge(0, 4).is_some());
241        assert!(graph.find_edge(4, 5).is_some());
242        assert!(graph.find_edge(5, 3).is_some());
243        assert!(graph.find_edge(1, 5).is_some());
244
245        // non-existing edge within ranges
246        assert_eq!(graph.find_edge_unchecked(0, 0), EdgeID::MAX);
247        assert!(graph.find_edge(0, 0).is_none());
248
249        // non-existing edge out of range
250        assert_eq!(graph.find_edge_unchecked(16, 17), EdgeID::MAX);
251        assert!(graph.find_edge(16, 17).is_none());
252    }
253}