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 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 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 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 graph.node_array.reserve(number_of_nodes + 1);
66 graph.edge_array.reserve(number_of_edges);
67
68 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 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 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 assert_eq!(graph.find_edge_unchecked(0, 0), EdgeID::MAX);
247 assert!(graph.find_edge(0, 0).is_none());
248
249 assert_eq!(graph.find_edge_unchecked(16, 17), EdgeID::MAX);
251 assert!(graph.find_edge(16, 17).is_none());
252 }
253}