1#[derive(Debug, Clone)]
16pub struct GraphData {
17 pub(crate) n: usize,
18 pub(crate) out_offsets: Vec<usize>,
19 pub(crate) out_targets: Vec<usize>,
20 pub(crate) out_weights: Vec<f64>,
21 pub(crate) total_weight: f64,
22 pub(crate) total_node_weight: f64,
23 pub(crate) out_degree: Vec<f64>,
24 pub(crate) node_weight: Vec<f64>,
25 pub(crate) directed: bool,
26 pub(crate) in_offsets: Vec<usize>,
27 pub(crate) in_targets: Vec<usize>,
28 pub(crate) in_weights: Vec<f64>,
29 pub(crate) in_degree: Vec<f64>,
30}
31
32impl GraphData {
33 #[inline]
35 pub fn node_count(&self) -> usize {
36 self.n
37 }
38
39 #[inline]
41 pub fn total_weight(&self) -> f64 {
42 self.total_weight
43 }
44
45 #[inline]
47 pub fn total_node_weight(&self) -> f64 {
48 self.total_node_weight
49 }
50
51 #[inline]
53 pub fn is_directed(&self) -> bool {
54 self.directed
55 }
56
57 #[inline]
62 pub fn neighbors(&self, node: usize) -> impl Iterator<Item = (usize, f64)> + '_ {
63 let (targets, weights) = self.neighbor_slices(node);
64 targets
65 .iter()
66 .zip(weights.iter())
67 .map(|(&t, &w)| (t, w))
68 }
69
70 #[inline]
75 pub fn neighbor_slices(&self, node: usize) -> (&[usize], &[f64]) {
76 if node >= self.n {
77 return (&[], &[]);
78 }
79 let start = self.out_offsets[node];
80 let end = self.out_offsets[node + 1];
81 (&self.out_targets[start..end], &self.out_weights[start..end])
82 }
83
84 #[inline]
89 pub fn degree_of(&self, node: usize) -> f64 {
90 if node >= self.n {
91 return 0.0;
92 }
93 if self.directed {
94 self.out_degree[node] + self.in_degree[node]
95 } else {
96 self.out_degree[node]
97 }
98 }
99
100 #[inline]
102 pub fn node_weight(&self, node: usize) -> f64 {
103 if node >= self.n {
104 return 0.0;
105 }
106 self.node_weight[node]
107 }
108
109 #[inline]
113 pub fn out_neighbors(&self, node: usize) -> impl Iterator<Item = (usize, f64)> + '_ {
114 let (targets, weights) = self.out_neighbor_slices(node);
115 targets
116 .iter()
117 .zip(weights.iter())
118 .map(|(&t, &w)| (t, w))
119 }
120
121 #[inline]
123 pub fn out_neighbor_slices(&self, node: usize) -> (&[usize], &[f64]) {
124 if node >= self.n {
125 return (&[], &[]);
126 }
127 let start = self.out_offsets[node];
128 let end = self.out_offsets[node + 1];
129 (&self.out_targets[start..end], &self.out_weights[start..end])
130 }
131
132 #[inline]
134 pub fn out_degree_of(&self, node: usize) -> f64 {
135 if node >= self.n {
136 return 0.0;
137 }
138 self.out_degree[node]
139 }
140
141 #[inline]
147 pub fn in_neighbors(&self, node: usize) -> impl Iterator<Item = (usize, f64)> + '_ {
148 let (targets, weights) = self.in_neighbor_slices(node);
149 targets.iter().zip(weights.iter()).map(|(&t, &w)| (t, w))
150 }
151
152 #[inline]
156 pub fn in_neighbor_slices(&self, node: usize) -> (&[usize], &[f64]) {
157 if self.directed && node < self.in_offsets.len() - 1 {
158 let start = self.in_offsets[node];
159 let end = self.in_offsets[node + 1];
160 (&self.in_targets[start..end], &self.in_weights[start..end])
161 } else {
162 (&[], &[])
163 }
164 }
165
166 #[inline]
170 pub fn in_degree_of(&self, node: usize) -> f64 {
171 if self.directed && node < self.in_degree.len() {
172 self.in_degree[node]
173 } else {
174 0.0
175 }
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use crate::graph::GraphDataBuilder;
183
184 fn make_graph() -> GraphData {
185 let mut b = GraphDataBuilder::new(3);
186 b.add_edge(0, 1, 1.0).unwrap();
187 b.add_edge(1, 2, 2.0).unwrap();
188 b.build().unwrap()
189 }
190
191 #[test]
193 fn in_neighbors_ok_on_oob_node() {
194 let g = make_graph();
195 let v: Vec<_> = g.in_neighbors(3).collect();
196 assert!(v.is_empty());
197 }
198
199 #[test]
201 fn in_neighbor_slices_ok_on_oob_node() {
202 let g = make_graph();
203 let (t, w) = g.in_neighbor_slices(3);
204 assert!(t.is_empty());
205 assert!(w.is_empty());
206 }
207
208 #[test]
210 fn in_degree_of_ok_on_oob_node() {
211 let g = make_graph();
212 assert_eq!(g.in_degree_of(3), 0.0);
213 }
214
215 #[test]
218 fn neighbors_returns_empty_for_oob() {
219 let g = make_graph();
220 let v: Vec<_> = g.neighbors(3).collect();
221 assert!(v.is_empty());
222 let v2: Vec<_> = g.neighbors(usize::MAX).collect();
223 assert!(v2.is_empty());
224 }
225
226 #[test]
227 fn neighbor_slices_returns_empty_for_oob() {
228 let g = make_graph();
229 let (t, w) = g.neighbor_slices(3);
230 assert!(t.is_empty());
231 assert!(w.is_empty());
232 }
233
234 #[test]
235 fn degree_of_returns_zero_for_oob() {
236 let g = make_graph();
237 assert_eq!(g.degree_of(3), 0.0);
238 }
239
240 #[test]
241 fn node_weight_returns_zero_for_oob() {
242 let g = make_graph();
243 assert_eq!(g.node_weight(3), 0.0);
244 }
245
246 #[test]
247 fn out_neighbors_returns_empty_for_oob() {
248 let g = make_graph();
249 let v: Vec<_> = g.out_neighbors(3).collect();
250 assert!(v.is_empty());
251 }
252
253 #[test]
254 fn out_neighbor_slices_returns_empty_for_oob() {
255 let g = make_graph();
256 let (t, w) = g.out_neighbor_slices(3);
257 assert!(t.is_empty());
258 assert!(w.is_empty());
259 }
260
261 #[test]
262 fn out_degree_of_returns_zero_for_oob() {
263 let g = make_graph();
264 assert_eq!(g.out_degree_of(3), 0.0);
265 }
266
267 #[test]
270 fn valid_neighbors_still_work() {
271 let g = make_graph();
272 let v: Vec<_> = g.neighbors(0).collect();
273 assert_eq!(v, vec![(1, 1.0)]);
274 let v2: Vec<_> = g.neighbors(1).collect();
275 assert_eq!(v2.len(), 2);
277 }
278
279 #[test]
280 fn valid_neighbor_slices_still_work() {
281 let g = make_graph();
282 let (t, w) = g.neighbor_slices(0);
283 assert_eq!(t.len(), 1);
284 assert_eq!(w.len(), 1);
285 }
286
287 #[test]
288 fn valid_degree_of_still_works() {
289 let g = make_graph();
290 assert_eq!(g.degree_of(0), 1.0);
292 }
293
294 #[test]
295 fn valid_node_weight_still_works() {
296 let g = make_graph();
297 assert_eq!(g.node_weight(0), 1.0);
298 }
299}