1use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct TemporalEdgeLayer {
22 successors: Vec<Option<u32>>,
24 predecessors: Vec<Option<u32>>,
26}
27
28impl TemporalEdgeLayer {
29 pub fn new() -> Self {
31 Self {
32 successors: Vec::new(),
33 predecessors: Vec::new(),
34 }
35 }
36
37 pub fn with_capacity(capacity: usize) -> Self {
39 Self {
40 successors: Vec::with_capacity(capacity),
41 predecessors: Vec::with_capacity(capacity),
42 }
43 }
44
45 pub fn register(&mut self, node_id: u32, entity_last_node: Option<u32>) {
54 assert_eq!(
55 node_id as usize,
56 self.successors.len(),
57 "nodes must be registered sequentially"
58 );
59
60 self.successors.push(None);
62 self.predecessors.push(entity_last_node);
64
65 if let Some(prev) = entity_last_node {
67 if (prev as usize) < self.successors.len() {
68 self.successors[prev as usize] = Some(node_id);
69 }
70 }
71 }
72
73 pub fn successor(&self, node_id: u32) -> Option<u32> {
75 self.successors.get(node_id as usize).copied().flatten()
76 }
77
78 pub fn predecessor(&self, node_id: u32) -> Option<u32> {
80 self.predecessors.get(node_id as usize).copied().flatten()
81 }
82
83 pub fn temporal_neighbors(&self, node_id: u32) -> impl Iterator<Item = u32> + '_ {
85 let pred = self.predecessor(node_id);
86 let succ = self.successor(node_id);
87 pred.into_iter().chain(succ)
88 }
89
90 pub fn walk_forward(&self, start: u32, max_steps: usize) -> Vec<u32> {
92 let mut path = Vec::with_capacity(max_steps);
93 let mut current = start;
94 for _ in 0..max_steps {
95 match self.successor(current) {
96 Some(next) => {
97 path.push(next);
98 current = next;
99 }
100 None => break,
101 }
102 }
103 path
104 }
105
106 pub fn walk_backward(&self, start: u32, max_steps: usize) -> Vec<u32> {
108 let mut path = Vec::with_capacity(max_steps);
109 let mut current = start;
110 for _ in 0..max_steps {
111 match self.predecessor(current) {
112 Some(prev) => {
113 path.push(prev);
114 current = prev;
115 }
116 None => break,
117 }
118 }
119 path
120 }
121
122 pub fn len(&self) -> usize {
124 self.successors.len()
125 }
126
127 pub fn is_empty(&self) -> bool {
129 self.successors.is_empty()
130 }
131
132 pub fn memory_bytes(&self) -> usize {
134 self.successors.len() * 8 + self.predecessors.len() * 8
136 }
137}
138
139impl Default for TemporalEdgeLayer {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
154 fn new_empty() {
155 let layer = TemporalEdgeLayer::new();
156 assert_eq!(layer.len(), 0);
157 assert!(layer.is_empty());
158 }
159
160 #[test]
161 fn register_single_node_no_predecessor() {
162 let mut layer = TemporalEdgeLayer::new();
163 layer.register(0, None);
164
165 assert_eq!(layer.len(), 1);
166 assert_eq!(layer.successor(0), None);
167 assert_eq!(layer.predecessor(0), None);
168 }
169
170 #[test]
173 fn single_entity_chain() {
174 let mut layer = TemporalEdgeLayer::new();
175
176 layer.register(0, None); layer.register(1, Some(0)); layer.register(2, Some(1)); layer.register(3, Some(2)); layer.register(4, Some(3)); assert_eq!(layer.successor(0), Some(1));
185 assert_eq!(layer.successor(1), Some(2));
186 assert_eq!(layer.successor(2), Some(3));
187 assert_eq!(layer.successor(3), Some(4));
188 assert_eq!(layer.successor(4), None); assert_eq!(layer.predecessor(0), None); assert_eq!(layer.predecessor(1), Some(0));
193 assert_eq!(layer.predecessor(2), Some(1));
194 assert_eq!(layer.predecessor(3), Some(2));
195 assert_eq!(layer.predecessor(4), Some(3));
196 }
197
198 #[test]
201 fn multi_entity_edges_dont_cross() {
202 let mut layer = TemporalEdgeLayer::new();
203
204 layer.register(0, None); layer.register(1, None); layer.register(2, Some(0)); layer.register(3, Some(1)); layer.register(4, Some(2)); layer.register(5, Some(3)); assert_eq!(layer.successor(0), Some(2));
216 assert_eq!(layer.successor(2), Some(4));
217 assert_eq!(layer.successor(4), None);
218 assert_eq!(layer.predecessor(4), Some(2));
219 assert_eq!(layer.predecessor(2), Some(0));
220
221 assert_eq!(layer.successor(1), Some(3));
223 assert_eq!(layer.successor(3), Some(5));
224 assert_eq!(layer.successor(5), None);
225 assert_eq!(layer.predecessor(5), Some(3));
226 assert_eq!(layer.predecessor(3), Some(1));
227
228 assert_ne!(layer.successor(0), Some(1)); assert_ne!(layer.successor(1), Some(2)); }
232
233 #[test]
236 fn walk_forward_full_chain() {
237 let mut layer = TemporalEdgeLayer::new();
238 for i in 0..5u32 {
239 layer.register(i, if i == 0 { None } else { Some(i - 1) });
240 }
241
242 let path = layer.walk_forward(0, 10);
243 assert_eq!(path, vec![1, 2, 3, 4]);
244 }
245
246 #[test]
247 fn walk_forward_limited() {
248 let mut layer = TemporalEdgeLayer::new();
249 for i in 0..10u32 {
250 layer.register(i, if i == 0 { None } else { Some(i - 1) });
251 }
252
253 let path = layer.walk_forward(0, 3);
254 assert_eq!(path, vec![1, 2, 3]);
255 }
256
257 #[test]
258 fn walk_forward_from_end() {
259 let mut layer = TemporalEdgeLayer::new();
260 layer.register(0, None);
261 layer.register(1, Some(0));
262
263 let path = layer.walk_forward(1, 5);
264 assert!(path.is_empty());
265 }
266
267 #[test]
268 fn walk_backward_full_chain() {
269 let mut layer = TemporalEdgeLayer::new();
270 for i in 0..5u32 {
271 layer.register(i, if i == 0 { None } else { Some(i - 1) });
272 }
273
274 let path = layer.walk_backward(4, 10);
275 assert_eq!(path, vec![3, 2, 1, 0]);
276 }
277
278 #[test]
279 fn walk_backward_limited() {
280 let mut layer = TemporalEdgeLayer::new();
281 for i in 0..10u32 {
282 layer.register(i, if i == 0 { None } else { Some(i - 1) });
283 }
284
285 let path = layer.walk_backward(9, 3);
286 assert_eq!(path, vec![8, 7, 6]);
287 }
288
289 #[test]
292 fn temporal_neighbors_middle_node() {
293 let mut layer = TemporalEdgeLayer::new();
294 layer.register(0, None);
295 layer.register(1, Some(0));
296 layer.register(2, Some(1));
297
298 let neighbors: Vec<u32> = layer.temporal_neighbors(1).collect();
299 assert_eq!(neighbors.len(), 2);
300 assert!(neighbors.contains(&0)); assert!(neighbors.contains(&2)); }
303
304 #[test]
305 fn temporal_neighbors_first_node() {
306 let mut layer = TemporalEdgeLayer::new();
307 layer.register(0, None);
308 layer.register(1, Some(0));
309
310 let neighbors: Vec<u32> = layer.temporal_neighbors(0).collect();
311 assert_eq!(neighbors.len(), 1); assert_eq!(neighbors[0], 1);
313 }
314
315 #[test]
316 fn temporal_neighbors_last_node() {
317 let mut layer = TemporalEdgeLayer::new();
318 layer.register(0, None);
319 layer.register(1, Some(0));
320
321 let neighbors: Vec<u32> = layer.temporal_neighbors(1).collect();
322 assert_eq!(neighbors.len(), 1); assert_eq!(neighbors[0], 0);
324 }
325
326 #[test]
327 fn temporal_neighbors_isolated_node() {
328 let mut layer = TemporalEdgeLayer::new();
329 layer.register(0, None); let neighbors: Vec<u32> = layer.temporal_neighbors(0).collect();
332 assert!(neighbors.is_empty());
333 }
334
335 #[test]
338 fn out_of_bounds_queries() {
339 let layer = TemporalEdgeLayer::new();
340 assert_eq!(layer.successor(999), None);
341 assert_eq!(layer.predecessor(999), None);
342 }
343
344 #[test]
345 fn walk_from_nonexistent() {
346 let layer = TemporalEdgeLayer::new();
347 assert!(layer.walk_forward(999, 5).is_empty());
348 assert!(layer.walk_backward(999, 5).is_empty());
349 }
350
351 #[test]
352 #[should_panic(expected = "nodes must be registered sequentially")]
353 fn register_out_of_order_panics() {
354 let mut layer = TemporalEdgeLayer::new();
355 layer.register(5, None); }
357
358 #[test]
361 fn memory_scales_linearly() {
362 let mut layer = TemporalEdgeLayer::new();
363 for i in 0..1000u32 {
364 layer.register(i, if i == 0 { None } else { Some(i - 1) });
365 }
366 let bytes = layer.memory_bytes();
367 assert_eq!(bytes, 16000);
369 }
370
371 #[test]
374 fn serialize_deserialize_roundtrip() {
375 let mut layer = TemporalEdgeLayer::new();
376 layer.register(0, None);
377 layer.register(1, Some(0));
378 layer.register(2, Some(1));
379
380 let bytes = postcard::to_allocvec(&layer).unwrap();
381 let restored: TemporalEdgeLayer = postcard::from_bytes(&bytes).unwrap();
382
383 assert_eq!(restored.len(), 3);
384 assert_eq!(restored.successor(0), Some(1));
385 assert_eq!(restored.successor(1), Some(2));
386 assert_eq!(restored.predecessor(2), Some(1));
387 }
388}